@antseed/node 0.1.0 → 0.1.2

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.
Files changed (140) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +7 -5
  3. package/dist/discovery/http-metadata-resolver.d.ts +6 -0
  4. package/dist/discovery/http-metadata-resolver.d.ts.map +1 -1
  5. package/dist/discovery/http-metadata-resolver.js +32 -4
  6. package/dist/discovery/http-metadata-resolver.js.map +1 -1
  7. package/dist/discovery/peer-lookup.d.ts +1 -0
  8. package/dist/discovery/peer-lookup.d.ts.map +1 -1
  9. package/dist/discovery/peer-lookup.js +10 -25
  10. package/dist/discovery/peer-lookup.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/interfaces/seller-provider.d.ts +13 -1
  16. package/dist/interfaces/seller-provider.d.ts.map +1 -1
  17. package/dist/node.d.ts +13 -3
  18. package/dist/node.d.ts.map +1 -1
  19. package/dist/node.js +146 -21
  20. package/dist/node.js.map +1 -1
  21. package/dist/proxy/proxy-mux.d.ts +3 -1
  22. package/dist/proxy/proxy-mux.d.ts.map +1 -1
  23. package/dist/proxy/proxy-mux.js +9 -5
  24. package/dist/proxy/proxy-mux.js.map +1 -1
  25. package/dist/types/http.d.ts +1 -0
  26. package/dist/types/http.d.ts.map +1 -1
  27. package/dist/types/http.js +1 -1
  28. package/dist/types/http.js.map +1 -1
  29. package/package.json +14 -10
  30. package/contracts/AntseedEscrow.sol +0 -310
  31. package/contracts/MockUSDC.sol +0 -64
  32. package/contracts/README.md +0 -102
  33. package/src/config/encryption.test.ts +0 -49
  34. package/src/config/encryption.ts +0 -53
  35. package/src/config/plugin-config-manager.test.ts +0 -92
  36. package/src/config/plugin-config-manager.ts +0 -153
  37. package/src/config/plugin-loader.ts +0 -90
  38. package/src/discovery/announcer.ts +0 -169
  39. package/src/discovery/bootstrap.ts +0 -57
  40. package/src/discovery/default-metadata-resolver.ts +0 -18
  41. package/src/discovery/dht-health.ts +0 -136
  42. package/src/discovery/dht-node.ts +0 -191
  43. package/src/discovery/http-metadata-resolver.ts +0 -47
  44. package/src/discovery/index.ts +0 -15
  45. package/src/discovery/metadata-codec.ts +0 -453
  46. package/src/discovery/metadata-resolver.ts +0 -7
  47. package/src/discovery/metadata-server.ts +0 -73
  48. package/src/discovery/metadata-validator.ts +0 -172
  49. package/src/discovery/peer-lookup.ts +0 -122
  50. package/src/discovery/peer-metadata.ts +0 -34
  51. package/src/discovery/peer-selector.ts +0 -134
  52. package/src/discovery/profile-manager.ts +0 -131
  53. package/src/discovery/profile-search.ts +0 -100
  54. package/src/discovery/reputation-verifier.ts +0 -54
  55. package/src/index.ts +0 -61
  56. package/src/interfaces/buyer-router.ts +0 -21
  57. package/src/interfaces/plugin.ts +0 -36
  58. package/src/interfaces/seller-provider.ts +0 -81
  59. package/src/metering/index.ts +0 -6
  60. package/src/metering/receipt-generator.ts +0 -105
  61. package/src/metering/receipt-verifier.ts +0 -102
  62. package/src/metering/session-tracker.ts +0 -145
  63. package/src/metering/storage.ts +0 -600
  64. package/src/metering/token-counter.ts +0 -127
  65. package/src/metering/usage-aggregator.ts +0 -236
  66. package/src/node.ts +0 -1698
  67. package/src/p2p/connection-auth.ts +0 -152
  68. package/src/p2p/connection-manager.ts +0 -916
  69. package/src/p2p/handshake.ts +0 -162
  70. package/src/p2p/ice-config.ts +0 -59
  71. package/src/p2p/identity.ts +0 -110
  72. package/src/p2p/index.ts +0 -11
  73. package/src/p2p/keepalive.ts +0 -118
  74. package/src/p2p/message-protocol.ts +0 -171
  75. package/src/p2p/nat-traversal.ts +0 -169
  76. package/src/p2p/payment-codec.ts +0 -165
  77. package/src/p2p/payment-mux.ts +0 -153
  78. package/src/p2p/reconnect.ts +0 -117
  79. package/src/payments/balance-manager.ts +0 -77
  80. package/src/payments/buyer-payment-manager.ts +0 -414
  81. package/src/payments/disputes.ts +0 -72
  82. package/src/payments/evm/escrow-client.ts +0 -263
  83. package/src/payments/evm/keypair.ts +0 -31
  84. package/src/payments/evm/signatures.ts +0 -103
  85. package/src/payments/evm/wallet.ts +0 -42
  86. package/src/payments/index.ts +0 -50
  87. package/src/payments/settlement.ts +0 -40
  88. package/src/payments/types.ts +0 -79
  89. package/src/proxy/index.ts +0 -3
  90. package/src/proxy/provider-detection.ts +0 -78
  91. package/src/proxy/proxy-mux.ts +0 -173
  92. package/src/proxy/request-codec.ts +0 -294
  93. package/src/reputation/index.ts +0 -6
  94. package/src/reputation/rating-manager.ts +0 -118
  95. package/src/reputation/report-manager.ts +0 -91
  96. package/src/reputation/trust-engine.ts +0 -120
  97. package/src/reputation/trust-score.ts +0 -74
  98. package/src/reputation/uptime-tracker.ts +0 -155
  99. package/src/routing/default-router.ts +0 -75
  100. package/src/types/bittorrent-dht.d.ts +0 -19
  101. package/src/types/buyer.ts +0 -37
  102. package/src/types/capability.ts +0 -34
  103. package/src/types/connection.ts +0 -29
  104. package/src/types/http.ts +0 -20
  105. package/src/types/index.ts +0 -14
  106. package/src/types/metering.ts +0 -175
  107. package/src/types/nat-api.d.ts +0 -29
  108. package/src/types/peer-profile.ts +0 -25
  109. package/src/types/peer.ts +0 -62
  110. package/src/types/plugin-config.ts +0 -31
  111. package/src/types/protocol.ts +0 -162
  112. package/src/types/provider.ts +0 -40
  113. package/src/types/rating.ts +0 -23
  114. package/src/types/report.ts +0 -30
  115. package/src/types/seller.ts +0 -38
  116. package/src/types/staking.ts +0 -23
  117. package/src/utils/debug.ts +0 -30
  118. package/src/utils/hex.ts +0 -14
  119. package/tests/balance-manager.test.ts +0 -156
  120. package/tests/bootstrap.test.ts +0 -108
  121. package/tests/buyer-payment-manager.test.ts +0 -358
  122. package/tests/connection-auth.test.ts +0 -87
  123. package/tests/default-router.test.ts +0 -148
  124. package/tests/evm-keypair.test.ts +0 -173
  125. package/tests/identity.test.ts +0 -133
  126. package/tests/message-protocol.test.ts +0 -212
  127. package/tests/metadata-codec.test.ts +0 -165
  128. package/tests/metadata-validator.test.ts +0 -261
  129. package/tests/metering-storage.test.ts +0 -244
  130. package/tests/payment-codec.test.ts +0 -95
  131. package/tests/payment-mux.test.ts +0 -191
  132. package/tests/peer-selector.test.ts +0 -184
  133. package/tests/provider-detection.test.ts +0 -107
  134. package/tests/proxy-mux-security.test.ts +0 -38
  135. package/tests/receipt.test.ts +0 -215
  136. package/tests/reputation-integration.test.ts +0 -195
  137. package/tests/request-codec.test.ts +0 -144
  138. package/tests/token-counter.test.ts +0 -122
  139. package/tsconfig.json +0 -9
  140. package/vitest.config.ts +0 -7
@@ -1,600 +0,0 @@
1
- import Database from 'better-sqlite3';
2
- import type {
3
- MeteringEvent,
4
- UsageReceipt,
5
- ReceiptVerification,
6
- SessionMetrics,
7
- TokenCount,
8
- } from '../types/metering.js';
9
-
10
- /**
11
- * SQLite storage for metering data.
12
- * All data is stored locally on the user's machine.
13
- */
14
- export class MeteringStorage {
15
- private readonly db: Database.Database;
16
-
17
- /**
18
- * Open or create the SQLite database at the given path.
19
- * Creates tables if they don't exist.
20
- *
21
- * @param dbPath - Path to the SQLite database file (or ':memory:' for tests)
22
- */
23
- constructor(dbPath: string) {
24
- this.db = new Database(dbPath);
25
- this.db.pragma('journal_mode = WAL');
26
- this.initializeSchema();
27
- }
28
-
29
- /**
30
- * Create tables and indices if they don't exist.
31
- */
32
- private initializeSchema(): void {
33
- this.db.exec(`
34
- CREATE TABLE IF NOT EXISTS metering_events (
35
- event_id TEXT PRIMARY KEY,
36
- session_id TEXT NOT NULL,
37
- timestamp INTEGER NOT NULL,
38
- provider TEXT NOT NULL,
39
- seller_peer_id TEXT NOT NULL,
40
- buyer_peer_id TEXT NOT NULL,
41
- input_tokens INTEGER NOT NULL,
42
- output_tokens INTEGER NOT NULL,
43
- total_tokens INTEGER NOT NULL,
44
- token_method TEXT NOT NULL,
45
- token_confidence TEXT NOT NULL,
46
- latency_ms INTEGER NOT NULL,
47
- status_code INTEGER NOT NULL,
48
- was_streaming INTEGER NOT NULL
49
- );
50
-
51
- CREATE INDEX IF NOT EXISTS idx_events_session ON metering_events(session_id);
52
- CREATE INDEX IF NOT EXISTS idx_events_timestamp ON metering_events(timestamp);
53
-
54
- CREATE TABLE IF NOT EXISTS usage_receipts (
55
- receipt_id TEXT PRIMARY KEY,
56
- session_id TEXT NOT NULL,
57
- event_id TEXT NOT NULL,
58
- timestamp INTEGER NOT NULL,
59
- provider TEXT NOT NULL,
60
- seller_peer_id TEXT NOT NULL,
61
- buyer_peer_id TEXT NOT NULL,
62
- input_tokens INTEGER NOT NULL,
63
- output_tokens INTEGER NOT NULL,
64
- total_tokens INTEGER NOT NULL,
65
- token_method TEXT NOT NULL,
66
- token_confidence TEXT NOT NULL,
67
- unit_price_cents_per_thousand_tokens INTEGER NOT NULL,
68
- cost_cents INTEGER NOT NULL,
69
- signature TEXT NOT NULL
70
- );
71
-
72
- CREATE INDEX IF NOT EXISTS idx_receipts_session ON usage_receipts(session_id);
73
- CREATE INDEX IF NOT EXISTS idx_receipts_timestamp ON usage_receipts(timestamp);
74
-
75
- CREATE TABLE IF NOT EXISTS receipt_verifications (
76
- receipt_id TEXT PRIMARY KEY,
77
- signature_valid INTEGER NOT NULL,
78
- buyer_input_tokens INTEGER NOT NULL,
79
- buyer_output_tokens INTEGER NOT NULL,
80
- buyer_total_tokens INTEGER NOT NULL,
81
- seller_total_tokens INTEGER NOT NULL,
82
- token_difference INTEGER NOT NULL,
83
- percentage_difference REAL NOT NULL,
84
- disputed INTEGER NOT NULL,
85
- verified_at INTEGER NOT NULL
86
- );
87
-
88
- CREATE TABLE IF NOT EXISTS sessions (
89
- session_id TEXT PRIMARY KEY,
90
- seller_peer_id TEXT NOT NULL,
91
- buyer_peer_id TEXT NOT NULL,
92
- provider TEXT NOT NULL,
93
- started_at INTEGER NOT NULL,
94
- ended_at INTEGER,
95
- total_requests INTEGER NOT NULL,
96
- total_tokens INTEGER NOT NULL,
97
- total_cost_cents INTEGER NOT NULL,
98
- avg_latency_ms REAL NOT NULL,
99
- peer_switches INTEGER NOT NULL,
100
- disputed_receipts INTEGER NOT NULL
101
- );
102
-
103
- CREATE INDEX IF NOT EXISTS idx_sessions_started ON sessions(started_at);
104
- CREATE INDEX IF NOT EXISTS idx_sessions_provider ON sessions(provider);
105
- `);
106
- }
107
-
108
- // --- Metering Events ---
109
-
110
- /** Insert a metering event. */
111
- insertEvent(event: MeteringEvent): void {
112
- const stmt = this.db.prepare(`
113
- INSERT INTO metering_events (
114
- event_id, session_id, timestamp, provider,
115
- seller_peer_id, buyer_peer_id,
116
- input_tokens, output_tokens, total_tokens,
117
- token_method, token_confidence,
118
- latency_ms, status_code, was_streaming
119
- ) VALUES (
120
- @eventId, @sessionId, @timestamp, @provider,
121
- @sellerPeerId, @buyerPeerId,
122
- @inputTokens, @outputTokens, @totalTokens,
123
- @tokenMethod, @tokenConfidence,
124
- @latencyMs, @statusCode, @wasStreaming
125
- )
126
- `);
127
-
128
- stmt.run({
129
- eventId: event.eventId,
130
- sessionId: event.sessionId,
131
- timestamp: event.timestamp,
132
- provider: event.provider,
133
- sellerPeerId: event.sellerPeerId,
134
- buyerPeerId: event.buyerPeerId,
135
- inputTokens: event.tokens.inputTokens,
136
- outputTokens: event.tokens.outputTokens,
137
- totalTokens: event.tokens.totalTokens,
138
- tokenMethod: event.tokens.method,
139
- tokenConfidence: event.tokens.confidence,
140
- latencyMs: event.latencyMs,
141
- statusCode: event.statusCode,
142
- wasStreaming: event.wasStreaming ? 1 : 0,
143
- });
144
- }
145
-
146
- /** Get events for a session. */
147
- getEventsBySession(sessionId: string): MeteringEvent[] {
148
- const stmt = this.db.prepare(
149
- 'SELECT * FROM metering_events WHERE session_id = ? ORDER BY timestamp'
150
- );
151
- const rows = stmt.all(sessionId) as EventRow[];
152
- return rows.map(rowToEvent);
153
- }
154
-
155
- /** Get events in a time range. */
156
- getEventsByTimeRange(startMs: number, endMs: number): MeteringEvent[] {
157
- const stmt = this.db.prepare(
158
- 'SELECT * FROM metering_events WHERE timestamp >= ? AND timestamp < ? ORDER BY timestamp'
159
- );
160
- const rows = stmt.all(startMs, endMs) as EventRow[];
161
- return rows.map(rowToEvent);
162
- }
163
-
164
- // --- Usage Receipts ---
165
-
166
- /** Insert a usage receipt. */
167
- insertReceipt(receipt: UsageReceipt): void {
168
- const stmt = this.db.prepare(`
169
- INSERT INTO usage_receipts (
170
- receipt_id, session_id, event_id, timestamp, provider,
171
- seller_peer_id, buyer_peer_id,
172
- input_tokens, output_tokens, total_tokens,
173
- token_method, token_confidence,
174
- unit_price_cents_per_thousand_tokens, cost_cents, signature
175
- ) VALUES (
176
- @receiptId, @sessionId, @eventId, @timestamp, @provider,
177
- @sellerPeerId, @buyerPeerId,
178
- @inputTokens, @outputTokens, @totalTokens,
179
- @tokenMethod, @tokenConfidence,
180
- @unitPriceCentsPerThousandTokens, @costCents, @signature
181
- )
182
- `);
183
-
184
- stmt.run({
185
- receiptId: receipt.receiptId,
186
- sessionId: receipt.sessionId,
187
- eventId: receipt.eventId,
188
- timestamp: receipt.timestamp,
189
- provider: receipt.provider,
190
- sellerPeerId: receipt.sellerPeerId,
191
- buyerPeerId: receipt.buyerPeerId,
192
- inputTokens: receipt.tokens.inputTokens,
193
- outputTokens: receipt.tokens.outputTokens,
194
- totalTokens: receipt.tokens.totalTokens,
195
- tokenMethod: receipt.tokens.method,
196
- tokenConfidence: receipt.tokens.confidence,
197
- unitPriceCentsPerThousandTokens: receipt.unitPriceCentsPerThousandTokens,
198
- costCents: receipt.costCents,
199
- signature: receipt.signature,
200
- });
201
- }
202
-
203
- /** Get receipts for a session. */
204
- getReceiptsBySession(sessionId: string): UsageReceipt[] {
205
- const stmt = this.db.prepare(
206
- 'SELECT * FROM usage_receipts WHERE session_id = ? ORDER BY timestamp'
207
- );
208
- const rows = stmt.all(sessionId) as ReceiptRow[];
209
- return rows.map(rowToReceipt);
210
- }
211
-
212
- /** Get all receipts in a time range. */
213
- getReceiptsByTimeRange(startMs: number, endMs: number): UsageReceipt[] {
214
- const stmt = this.db.prepare(
215
- 'SELECT * FROM usage_receipts WHERE timestamp >= ? AND timestamp < ? ORDER BY timestamp'
216
- );
217
- const rows = stmt.all(startMs, endMs) as ReceiptRow[];
218
- return rows.map(rowToReceipt);
219
- }
220
-
221
- /** Get total cost in a time range (sum of costCents). */
222
- getTotalCost(startMs: number, endMs: number): number {
223
- const stmt = this.db.prepare(
224
- 'SELECT COALESCE(SUM(cost_cents), 0) as total FROM usage_receipts WHERE timestamp >= ? AND timestamp < ?'
225
- );
226
- const row = stmt.get(startMs, endMs) as { total: number };
227
- return row.total;
228
- }
229
-
230
- // --- Receipt Verifications ---
231
-
232
- /** Insert a verification result. */
233
- insertVerification(verification: ReceiptVerification): void {
234
- const stmt = this.db.prepare(`
235
- INSERT INTO receipt_verifications (
236
- receipt_id, signature_valid,
237
- buyer_input_tokens, buyer_output_tokens, buyer_total_tokens,
238
- seller_total_tokens,
239
- token_difference, percentage_difference,
240
- disputed, verified_at
241
- ) VALUES (
242
- @receiptId, @signatureValid,
243
- @buyerInputTokens, @buyerOutputTokens, @buyerTotalTokens,
244
- @sellerTotalTokens,
245
- @tokenDifference, @percentageDifference,
246
- @disputed, @verifiedAt
247
- )
248
- `);
249
-
250
- stmt.run({
251
- receiptId: verification.receiptId,
252
- signatureValid: verification.signatureValid ? 1 : 0,
253
- buyerInputTokens: verification.buyerTokenEstimate.inputTokens,
254
- buyerOutputTokens: verification.buyerTokenEstimate.outputTokens,
255
- buyerTotalTokens: verification.buyerTokenEstimate.totalTokens,
256
- sellerTotalTokens: verification.sellerTokenEstimate.totalTokens,
257
- tokenDifference: verification.tokenDifference,
258
- percentageDifference: verification.percentageDifference,
259
- disputed: verification.disputed ? 1 : 0,
260
- verifiedAt: verification.verifiedAt,
261
- });
262
- }
263
-
264
- /** Get all disputed verifications in a time range. */
265
- getDisputedVerifications(startMs: number, endMs: number): ReceiptVerification[] {
266
- const stmt = this.db.prepare(
267
- 'SELECT * FROM receipt_verifications WHERE disputed = 1 AND verified_at >= ? AND verified_at < ? ORDER BY verified_at'
268
- );
269
- const rows = stmt.all(startMs, endMs) as VerificationRow[];
270
- return rows.map(rowToVerification);
271
- }
272
-
273
- // --- Sessions ---
274
-
275
- /** Upsert session metrics (insert or update). */
276
- upsertSession(metrics: SessionMetrics): void {
277
- const stmt = this.db.prepare(`
278
- INSERT INTO sessions (
279
- session_id, seller_peer_id, buyer_peer_id, provider,
280
- started_at, ended_at,
281
- total_requests, total_tokens, total_cost_cents,
282
- avg_latency_ms, peer_switches, disputed_receipts
283
- ) VALUES (
284
- @sessionId, @sellerPeerId, @buyerPeerId, @provider,
285
- @startedAt, @endedAt,
286
- @totalRequests, @totalTokens, @totalCostCents,
287
- @avgLatencyMs, @peerSwitches, @disputedReceipts
288
- )
289
- ON CONFLICT(session_id) DO UPDATE SET
290
- ended_at = @endedAt,
291
- total_requests = @totalRequests,
292
- total_tokens = @totalTokens,
293
- total_cost_cents = @totalCostCents,
294
- avg_latency_ms = @avgLatencyMs,
295
- peer_switches = @peerSwitches,
296
- disputed_receipts = @disputedReceipts
297
- `);
298
-
299
- stmt.run({
300
- sessionId: metrics.sessionId,
301
- sellerPeerId: metrics.sellerPeerId,
302
- buyerPeerId: metrics.buyerPeerId,
303
- provider: metrics.provider,
304
- startedAt: metrics.startedAt,
305
- endedAt: metrics.endedAt,
306
- totalRequests: metrics.totalRequests,
307
- totalTokens: metrics.totalTokens,
308
- totalCostCents: metrics.totalCostCents,
309
- avgLatencyMs: metrics.avgLatencyMs,
310
- peerSwitches: metrics.peerSwitches,
311
- disputedReceipts: metrics.disputedReceipts,
312
- });
313
- }
314
-
315
- /** Get a session by ID. */
316
- getSession(sessionId: string): SessionMetrics | null {
317
- const stmt = this.db.prepare('SELECT * FROM sessions WHERE session_id = ?');
318
- const row = stmt.get(sessionId) as SessionRow | undefined;
319
- return row ? rowToSession(row) : null;
320
- }
321
-
322
- /** Get all sessions in a time range. */
323
- getSessionsByTimeRange(startMs: number, endMs: number): SessionMetrics[] {
324
- const stmt = this.db.prepare(
325
- 'SELECT * FROM sessions WHERE started_at >= ? AND started_at < ? ORDER BY started_at'
326
- );
327
- const rows = stmt.all(startMs, endMs) as SessionRow[];
328
- return rows.map(rowToSession);
329
- }
330
-
331
- /** Get session count and total cost for a time range. */
332
- getSessionSummary(startMs: number, endMs: number): {
333
- sessionCount: number;
334
- totalRequests: number;
335
- totalTokens: number;
336
- totalCostCents: number;
337
- } {
338
- const stmt = this.db.prepare(`
339
- SELECT
340
- COUNT(*) as session_count,
341
- COALESCE(SUM(total_requests), 0) as total_requests,
342
- COALESCE(SUM(total_tokens), 0) as total_tokens,
343
- COALESCE(SUM(total_cost_cents), 0) as total_cost_cents
344
- FROM sessions
345
- WHERE started_at >= ? AND started_at < ?
346
- `);
347
- const row = stmt.get(startMs, endMs) as {
348
- session_count: number;
349
- total_requests: number;
350
- total_tokens: number;
351
- total_cost_cents: number;
352
- };
353
- return {
354
- sessionCount: row.session_count,
355
- totalRequests: row.total_requests,
356
- totalTokens: row.total_tokens,
357
- totalCostCents: row.total_cost_cents,
358
- };
359
- }
360
-
361
- /** Get total tokens from metering events in a time range (real-time, per-request). */
362
- getEventTokenSummary(startMs: number, endMs: number): {
363
- totalRequests: number;
364
- totalTokens: number;
365
- inputTokens: number;
366
- outputTokens: number;
367
- } {
368
- const stmt = this.db.prepare(`
369
- SELECT
370
- COUNT(*) as total_requests,
371
- COALESCE(SUM(total_tokens), 0) as total_tokens,
372
- COALESCE(SUM(input_tokens), 0) as input_tokens,
373
- COALESCE(SUM(output_tokens), 0) as output_tokens
374
- FROM metering_events
375
- WHERE timestamp >= ? AND timestamp < ?
376
- `);
377
- const row = stmt.get(startMs, endMs) as {
378
- total_requests: number;
379
- total_tokens: number;
380
- input_tokens: number;
381
- output_tokens: number;
382
- };
383
- return {
384
- totalRequests: row.total_requests,
385
- totalTokens: row.total_tokens,
386
- inputTokens: row.input_tokens,
387
- outputTokens: row.output_tokens,
388
- };
389
- }
390
-
391
- // --- Maintenance ---
392
-
393
- /**
394
- * Delete data older than the given timestamp.
395
- * Used for storage maintenance / retention policy.
396
- */
397
- pruneOlderThan(timestampMs: number): {
398
- eventsDeleted: number;
399
- receiptsDeleted: number;
400
- verificationsDeleted: number;
401
- sessionsDeleted: number;
402
- } {
403
- const deleteEvents = this.db.prepare(
404
- 'DELETE FROM metering_events WHERE timestamp < ?'
405
- );
406
- const deleteReceipts = this.db.prepare(
407
- 'DELETE FROM usage_receipts WHERE timestamp < ?'
408
- );
409
- const deleteVerifications = this.db.prepare(
410
- 'DELETE FROM receipt_verifications WHERE verified_at < ?'
411
- );
412
- const deleteSessions = this.db.prepare(
413
- 'DELETE FROM sessions WHERE started_at < ?'
414
- );
415
-
416
- const eventsResult = deleteEvents.run(timestampMs);
417
- const receiptsResult = deleteReceipts.run(timestampMs);
418
- const verificationsResult = deleteVerifications.run(timestampMs);
419
- const sessionsResult = deleteSessions.run(timestampMs);
420
-
421
- return {
422
- eventsDeleted: eventsResult.changes,
423
- receiptsDeleted: receiptsResult.changes,
424
- verificationsDeleted: verificationsResult.changes,
425
- sessionsDeleted: sessionsResult.changes,
426
- };
427
- }
428
-
429
- /**
430
- * Close the database connection.
431
- */
432
- close(): void {
433
- this.db.close();
434
- }
435
- }
436
-
437
- // --- Row types for SQLite results ---
438
-
439
- interface EventRow {
440
- event_id: string;
441
- session_id: string;
442
- timestamp: number;
443
- provider: string;
444
- seller_peer_id: string;
445
- buyer_peer_id: string;
446
- input_tokens: number;
447
- output_tokens: number;
448
- total_tokens: number;
449
- token_method: string;
450
- token_confidence: string;
451
- latency_ms: number;
452
- status_code: number;
453
- was_streaming: number;
454
- }
455
-
456
- interface ReceiptRow {
457
- receipt_id: string;
458
- session_id: string;
459
- event_id: string;
460
- timestamp: number;
461
- provider: string;
462
- seller_peer_id: string;
463
- buyer_peer_id: string;
464
- input_tokens: number;
465
- output_tokens: number;
466
- total_tokens: number;
467
- token_method: string;
468
- token_confidence: string;
469
- unit_price_cents_per_thousand_tokens: number;
470
- cost_cents: number;
471
- signature: string;
472
- }
473
-
474
- interface VerificationRow {
475
- receipt_id: string;
476
- signature_valid: number;
477
- buyer_input_tokens: number;
478
- buyer_output_tokens: number;
479
- buyer_total_tokens: number;
480
- seller_total_tokens: number;
481
- token_difference: number;
482
- percentage_difference: number;
483
- disputed: number;
484
- verified_at: number;
485
- }
486
-
487
- interface SessionRow {
488
- session_id: string;
489
- seller_peer_id: string;
490
- buyer_peer_id: string;
491
- provider: string;
492
- started_at: number;
493
- ended_at: number | null;
494
- total_requests: number;
495
- total_tokens: number;
496
- total_cost_cents: number;
497
- avg_latency_ms: number;
498
- peer_switches: number;
499
- disputed_receipts: number;
500
- }
501
-
502
- // --- Row mapping functions ---
503
-
504
- const VALID_TOKEN_METHODS = new Set(['content-length', 'chunk-accumulation', 'fallback']);
505
- const VALID_TOKEN_CONFIDENCES = new Set(['high', 'medium', 'low']);
506
-
507
- function validateTokenMethod(value: string): TokenCount['method'] {
508
- if (VALID_TOKEN_METHODS.has(value)) return value as TokenCount['method'];
509
- return 'fallback';
510
- }
511
-
512
- function validateTokenConfidence(value: string): TokenCount['confidence'] {
513
- if (VALID_TOKEN_CONFIDENCES.has(value)) return value as TokenCount['confidence'];
514
- return 'low';
515
- }
516
-
517
- function rowToEvent(row: EventRow): MeteringEvent {
518
- return {
519
- eventId: row.event_id,
520
- sessionId: row.session_id,
521
- timestamp: row.timestamp,
522
- provider: row.provider,
523
- sellerPeerId: row.seller_peer_id,
524
- buyerPeerId: row.buyer_peer_id,
525
- tokens: {
526
- inputTokens: row.input_tokens,
527
- outputTokens: row.output_tokens,
528
- totalTokens: row.total_tokens,
529
- method: validateTokenMethod(row.token_method),
530
- confidence: validateTokenConfidence(row.token_confidence),
531
- },
532
- latencyMs: row.latency_ms,
533
- statusCode: row.status_code,
534
- wasStreaming: row.was_streaming === 1,
535
- };
536
- }
537
-
538
- function rowToReceipt(row: ReceiptRow): UsageReceipt {
539
- return {
540
- receiptId: row.receipt_id,
541
- sessionId: row.session_id,
542
- eventId: row.event_id,
543
- timestamp: row.timestamp,
544
- provider: row.provider,
545
- sellerPeerId: row.seller_peer_id,
546
- buyerPeerId: row.buyer_peer_id,
547
- tokens: {
548
- inputTokens: row.input_tokens,
549
- outputTokens: row.output_tokens,
550
- totalTokens: row.total_tokens,
551
- method: validateTokenMethod(row.token_method),
552
- confidence: validateTokenConfidence(row.token_confidence),
553
- },
554
- unitPriceCentsPerThousandTokens: row.unit_price_cents_per_thousand_tokens,
555
- costCents: row.cost_cents,
556
- signature: row.signature,
557
- };
558
- }
559
-
560
- function rowToVerification(row: VerificationRow): ReceiptVerification {
561
- return {
562
- receiptId: row.receipt_id,
563
- signatureValid: row.signature_valid === 1,
564
- buyerTokenEstimate: {
565
- inputTokens: row.buyer_input_tokens,
566
- outputTokens: row.buyer_output_tokens,
567
- totalTokens: row.buyer_total_tokens,
568
- method: 'content-length',
569
- confidence: 'high',
570
- },
571
- sellerTokenEstimate: {
572
- inputTokens: 0,
573
- outputTokens: 0,
574
- totalTokens: row.seller_total_tokens,
575
- method: 'content-length',
576
- confidence: 'high',
577
- },
578
- tokenDifference: row.token_difference,
579
- percentageDifference: row.percentage_difference,
580
- disputed: row.disputed === 1,
581
- verifiedAt: row.verified_at,
582
- };
583
- }
584
-
585
- function rowToSession(row: SessionRow): SessionMetrics {
586
- return {
587
- sessionId: row.session_id,
588
- sellerPeerId: row.seller_peer_id,
589
- buyerPeerId: row.buyer_peer_id,
590
- provider: row.provider,
591
- startedAt: row.started_at,
592
- endedAt: row.ended_at,
593
- totalRequests: row.total_requests,
594
- totalTokens: row.total_tokens,
595
- totalCostCents: row.total_cost_cents,
596
- avgLatencyMs: row.avg_latency_ms,
597
- peerSwitches: row.peer_switches,
598
- disputedReceipts: row.disputed_receipts,
599
- };
600
- }