@antseed/node 0.1.0 → 0.1.1
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/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/seller-provider.d.ts +13 -1
- package/dist/interfaces/seller-provider.d.ts.map +1 -1
- package/dist/node.d.ts +13 -3
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +123 -15
- package/dist/node.js.map +1 -1
- package/dist/proxy/proxy-mux.d.ts +3 -1
- package/dist/proxy/proxy-mux.d.ts.map +1 -1
- package/dist/proxy/proxy-mux.js +9 -5
- package/dist/proxy/proxy-mux.js.map +1 -1
- package/dist/types/http.d.ts +1 -0
- package/dist/types/http.d.ts.map +1 -1
- package/dist/types/http.js +1 -1
- package/dist/types/http.js.map +1 -1
- package/package.json +14 -10
- package/contracts/AntseedEscrow.sol +0 -310
- package/contracts/MockUSDC.sol +0 -64
- package/contracts/README.md +0 -102
- package/src/config/encryption.test.ts +0 -49
- package/src/config/encryption.ts +0 -53
- package/src/config/plugin-config-manager.test.ts +0 -92
- package/src/config/plugin-config-manager.ts +0 -153
- package/src/config/plugin-loader.ts +0 -90
- package/src/discovery/announcer.ts +0 -169
- package/src/discovery/bootstrap.ts +0 -57
- package/src/discovery/default-metadata-resolver.ts +0 -18
- package/src/discovery/dht-health.ts +0 -136
- package/src/discovery/dht-node.ts +0 -191
- package/src/discovery/http-metadata-resolver.ts +0 -47
- package/src/discovery/index.ts +0 -15
- package/src/discovery/metadata-codec.ts +0 -453
- package/src/discovery/metadata-resolver.ts +0 -7
- package/src/discovery/metadata-server.ts +0 -73
- package/src/discovery/metadata-validator.ts +0 -172
- package/src/discovery/peer-lookup.ts +0 -122
- package/src/discovery/peer-metadata.ts +0 -34
- package/src/discovery/peer-selector.ts +0 -134
- package/src/discovery/profile-manager.ts +0 -131
- package/src/discovery/profile-search.ts +0 -100
- package/src/discovery/reputation-verifier.ts +0 -54
- package/src/index.ts +0 -61
- package/src/interfaces/buyer-router.ts +0 -21
- package/src/interfaces/plugin.ts +0 -36
- package/src/interfaces/seller-provider.ts +0 -81
- package/src/metering/index.ts +0 -6
- package/src/metering/receipt-generator.ts +0 -105
- package/src/metering/receipt-verifier.ts +0 -102
- package/src/metering/session-tracker.ts +0 -145
- package/src/metering/storage.ts +0 -600
- package/src/metering/token-counter.ts +0 -127
- package/src/metering/usage-aggregator.ts +0 -236
- package/src/node.ts +0 -1698
- package/src/p2p/connection-auth.ts +0 -152
- package/src/p2p/connection-manager.ts +0 -916
- package/src/p2p/handshake.ts +0 -162
- package/src/p2p/ice-config.ts +0 -59
- package/src/p2p/identity.ts +0 -110
- package/src/p2p/index.ts +0 -11
- package/src/p2p/keepalive.ts +0 -118
- package/src/p2p/message-protocol.ts +0 -171
- package/src/p2p/nat-traversal.ts +0 -169
- package/src/p2p/payment-codec.ts +0 -165
- package/src/p2p/payment-mux.ts +0 -153
- package/src/p2p/reconnect.ts +0 -117
- package/src/payments/balance-manager.ts +0 -77
- package/src/payments/buyer-payment-manager.ts +0 -414
- package/src/payments/disputes.ts +0 -72
- package/src/payments/evm/escrow-client.ts +0 -263
- package/src/payments/evm/keypair.ts +0 -31
- package/src/payments/evm/signatures.ts +0 -103
- package/src/payments/evm/wallet.ts +0 -42
- package/src/payments/index.ts +0 -50
- package/src/payments/settlement.ts +0 -40
- package/src/payments/types.ts +0 -79
- package/src/proxy/index.ts +0 -3
- package/src/proxy/provider-detection.ts +0 -78
- package/src/proxy/proxy-mux.ts +0 -173
- package/src/proxy/request-codec.ts +0 -294
- package/src/reputation/index.ts +0 -6
- package/src/reputation/rating-manager.ts +0 -118
- package/src/reputation/report-manager.ts +0 -91
- package/src/reputation/trust-engine.ts +0 -120
- package/src/reputation/trust-score.ts +0 -74
- package/src/reputation/uptime-tracker.ts +0 -155
- package/src/routing/default-router.ts +0 -75
- package/src/types/bittorrent-dht.d.ts +0 -19
- package/src/types/buyer.ts +0 -37
- package/src/types/capability.ts +0 -34
- package/src/types/connection.ts +0 -29
- package/src/types/http.ts +0 -20
- package/src/types/index.ts +0 -14
- package/src/types/metering.ts +0 -175
- package/src/types/nat-api.d.ts +0 -29
- package/src/types/peer-profile.ts +0 -25
- package/src/types/peer.ts +0 -62
- package/src/types/plugin-config.ts +0 -31
- package/src/types/protocol.ts +0 -162
- package/src/types/provider.ts +0 -40
- package/src/types/rating.ts +0 -23
- package/src/types/report.ts +0 -30
- package/src/types/seller.ts +0 -38
- package/src/types/staking.ts +0 -23
- package/src/utils/debug.ts +0 -30
- package/src/utils/hex.ts +0 -14
- package/tests/balance-manager.test.ts +0 -156
- package/tests/bootstrap.test.ts +0 -108
- package/tests/buyer-payment-manager.test.ts +0 -358
- package/tests/connection-auth.test.ts +0 -87
- package/tests/default-router.test.ts +0 -148
- package/tests/evm-keypair.test.ts +0 -173
- package/tests/identity.test.ts +0 -133
- package/tests/message-protocol.test.ts +0 -212
- package/tests/metadata-codec.test.ts +0 -165
- package/tests/metadata-validator.test.ts +0 -261
- package/tests/metering-storage.test.ts +0 -244
- package/tests/payment-codec.test.ts +0 -95
- package/tests/payment-mux.test.ts +0 -191
- package/tests/peer-selector.test.ts +0 -184
- package/tests/provider-detection.test.ts +0 -107
- package/tests/proxy-mux-security.test.ts +0 -38
- package/tests/receipt.test.ts +0 -215
- package/tests/reputation-integration.test.ts +0 -195
- package/tests/request-codec.test.ts +0 -144
- package/tests/token-counter.test.ts +0 -122
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -7
package/src/metering/storage.ts
DELETED
|
@@ -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
|
-
}
|