@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.
- package/LICENSE +674 -0
- package/README.md +7 -5
- package/dist/discovery/http-metadata-resolver.d.ts +6 -0
- package/dist/discovery/http-metadata-resolver.d.ts.map +1 -1
- package/dist/discovery/http-metadata-resolver.js +32 -4
- package/dist/discovery/http-metadata-resolver.js.map +1 -1
- package/dist/discovery/peer-lookup.d.ts +1 -0
- package/dist/discovery/peer-lookup.d.ts.map +1 -1
- package/dist/discovery/peer-lookup.js +10 -25
- package/dist/discovery/peer-lookup.js.map +1 -1
- 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 +146 -21
- 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
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import type { SerializedHttpRequest, SerializedHttpResponse } from '../types/http.js';
|
|
2
|
-
import type { ProviderCapability } from '../types/capability.js';
|
|
3
|
-
|
|
4
|
-
export interface ProviderTokenPricingUsdPerMillion {
|
|
5
|
-
inputUsdPerMillion: number;
|
|
6
|
-
outputUsdPerMillion: number;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface ProviderPricing {
|
|
10
|
-
defaults: ProviderTokenPricingUsdPerMillion;
|
|
11
|
-
models?: Record<string, ProviderTokenPricingUsdPerMillion>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Interface that seller nodes implement to provide inference.
|
|
16
|
-
*
|
|
17
|
-
* Each provider represents one upstream LLM service (e.g., Anthropic, OpenAI, local LLM).
|
|
18
|
-
* The SDK handles P2P connections, discovery, metering, and payments.
|
|
19
|
-
* You just handle the HTTP request → response conversion.
|
|
20
|
-
*/
|
|
21
|
-
export interface Provider {
|
|
22
|
-
/** Unique name for this provider (e.g., 'anthropic', 'openai', 'my-local-llm') */
|
|
23
|
-
name: string;
|
|
24
|
-
|
|
25
|
-
/** Model IDs this provider supports (e.g., ['claude-sonnet-4-5-20250929', 'claude-opus-4-0-20250514']) */
|
|
26
|
-
models: string[];
|
|
27
|
-
|
|
28
|
-
/** Seller pricing in USD per 1M tokens (defaults + optional per-model overrides). */
|
|
29
|
-
pricing: ProviderPricing;
|
|
30
|
-
|
|
31
|
-
/** Maximum concurrent requests this provider can handle */
|
|
32
|
-
maxConcurrency: number;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Handle an incoming inference request and return the response.
|
|
36
|
-
*/
|
|
37
|
-
handleRequest(req: SerializedHttpRequest): Promise<SerializedHttpResponse>;
|
|
38
|
-
|
|
39
|
-
/** Optional startup hook — validate credentials, warm caches, etc. */
|
|
40
|
-
init?(): Promise<void>;
|
|
41
|
-
|
|
42
|
-
/** Return current and maximum concurrent request counts */
|
|
43
|
-
getCapacity(): { current: number; max: number };
|
|
44
|
-
|
|
45
|
-
/** Capabilities beyond inference (optional — defaults to ['inference']) */
|
|
46
|
-
capabilities?: ProviderCapability[];
|
|
47
|
-
|
|
48
|
-
/** Handle a long-running agent task. Returns an async iterable of events. */
|
|
49
|
-
handleTask?(task: TaskRequest): AsyncIterable<TaskEvent>;
|
|
50
|
-
|
|
51
|
-
/** Handle a one-shot skill request. */
|
|
52
|
-
handleSkill?(skill: SkillRequest): Promise<SkillResponse>;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface TaskRequest {
|
|
56
|
-
taskId: string;
|
|
57
|
-
capability: ProviderCapability;
|
|
58
|
-
input: unknown;
|
|
59
|
-
metadata?: Record<string, unknown>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface TaskEvent {
|
|
63
|
-
taskId: string;
|
|
64
|
-
type: 'status' | 'progress' | 'intermediate' | 'final';
|
|
65
|
-
data: unknown;
|
|
66
|
-
timestamp: number;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface SkillRequest {
|
|
70
|
-
skillId: string;
|
|
71
|
-
capability: ProviderCapability;
|
|
72
|
-
input: unknown;
|
|
73
|
-
inputSchema?: Record<string, unknown>;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface SkillResponse {
|
|
77
|
-
skillId: string;
|
|
78
|
-
output: unknown;
|
|
79
|
-
outputSchema?: Record<string, unknown>;
|
|
80
|
-
durationMs: number;
|
|
81
|
-
}
|
package/src/metering/index.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { estimateTokens, estimateTokensFromContentLength, estimateTokensFromStreamBytes, BYTES_PER_TOKEN, MIN_REQUEST_TOKENS, MIN_RESPONSE_TOKENS } from './token-counter.js';
|
|
2
|
-
export { MeteringStorage } from './storage.js';
|
|
3
|
-
export { ReceiptGenerator, buildSignaturePayload, calculateCost, type Signer } from './receipt-generator.js';
|
|
4
|
-
export { ReceiptVerifier, type SignatureVerifier, type VerifierOptions } from './receipt-verifier.js';
|
|
5
|
-
export { SessionTracker } from './session-tracker.js';
|
|
6
|
-
export { UsageAggregator, type AggregationGranularity, type TimePeriod } from './usage-aggregator.js';
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import type { ProviderType, TokenCount, UsageReceipt } from '../types/metering.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Interface for signing data with the seller's Ed25519 private key.
|
|
6
|
-
* The actual implementation lives in the identity module (PRD-01).
|
|
7
|
-
*/
|
|
8
|
-
export interface Signer {
|
|
9
|
-
/**
|
|
10
|
-
* Sign a message with the seller's Ed25519 private key.
|
|
11
|
-
* @param message - UTF-8 string to sign
|
|
12
|
-
* @returns Hex-encoded signature
|
|
13
|
-
*/
|
|
14
|
-
sign(message: string): string;
|
|
15
|
-
|
|
16
|
-
/** The seller's peer ID (Ed25519 public key hex) */
|
|
17
|
-
peerId: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Build the canonical string representation of receipt data for signing.
|
|
22
|
-
* The order and format must be deterministic so both sides produce the
|
|
23
|
-
* same string from the same receipt data.
|
|
24
|
-
*/
|
|
25
|
-
export function buildSignaturePayload(receipt: Omit<UsageReceipt, 'signature'>): string {
|
|
26
|
-
return [
|
|
27
|
-
receipt.receiptId,
|
|
28
|
-
receipt.sessionId,
|
|
29
|
-
receipt.eventId,
|
|
30
|
-
receipt.timestamp.toString(),
|
|
31
|
-
receipt.provider,
|
|
32
|
-
receipt.sellerPeerId,
|
|
33
|
-
receipt.buyerPeerId,
|
|
34
|
-
receipt.tokens.totalTokens.toString(),
|
|
35
|
-
receipt.costCents.toString(),
|
|
36
|
-
].join('|');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Calculate the cost in USD cents from token count and price.
|
|
41
|
-
*
|
|
42
|
-
* @param totalTokens - Total estimated tokens
|
|
43
|
-
* @param unitPriceCentsPerThousandTokens - Unit price in USD cents per 1,000 tokens
|
|
44
|
-
* @returns Cost in USD cents (rounded to nearest cent)
|
|
45
|
-
*/
|
|
46
|
-
export function calculateCost(totalTokens: number, unitPriceCentsPerThousandTokens: number): number {
|
|
47
|
-
const raw = (totalTokens / 1000) * unitPriceCentsPerThousandTokens;
|
|
48
|
-
return raw > 0 ? Math.max(1, Math.round(raw)) : 0;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Generates signed usage receipts for the seller side.
|
|
53
|
-
*/
|
|
54
|
-
export class ReceiptGenerator {
|
|
55
|
-
private readonly signer: Signer;
|
|
56
|
-
|
|
57
|
-
constructor(signer: Signer) {
|
|
58
|
-
this.signer = signer;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Generate a signed receipt for a completed request.
|
|
63
|
-
*
|
|
64
|
-
* @param sessionId - The buyer session ID
|
|
65
|
-
* @param eventId - The metering event ID
|
|
66
|
-
* @param provider - Provider used
|
|
67
|
-
* @param buyerPeerId - Buyer's peer ID
|
|
68
|
-
* @param tokens - Token estimate
|
|
69
|
-
* @param unitPriceCentsPerThousandTokens - Effective unit price in USD cents per 1,000 tokens
|
|
70
|
-
* @returns Signed UsageReceipt
|
|
71
|
-
*/
|
|
72
|
-
generate(
|
|
73
|
-
sessionId: string,
|
|
74
|
-
eventId: string,
|
|
75
|
-
provider: ProviderType,
|
|
76
|
-
buyerPeerId: string,
|
|
77
|
-
tokens: TokenCount,
|
|
78
|
-
unitPriceCentsPerThousandTokens: number
|
|
79
|
-
): UsageReceipt {
|
|
80
|
-
const receiptId = randomUUID();
|
|
81
|
-
const timestamp = Date.now();
|
|
82
|
-
const costCents = calculateCost(tokens.totalTokens, unitPriceCentsPerThousandTokens);
|
|
83
|
-
|
|
84
|
-
const receiptData: Omit<UsageReceipt, 'signature'> = {
|
|
85
|
-
receiptId,
|
|
86
|
-
sessionId,
|
|
87
|
-
eventId,
|
|
88
|
-
timestamp,
|
|
89
|
-
provider,
|
|
90
|
-
sellerPeerId: this.signer.peerId,
|
|
91
|
-
buyerPeerId,
|
|
92
|
-
tokens,
|
|
93
|
-
unitPriceCentsPerThousandTokens,
|
|
94
|
-
costCents,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const payload = buildSignaturePayload(receiptData);
|
|
98
|
-
const signature = this.signer.sign(payload);
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
...receiptData,
|
|
102
|
-
signature,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import type { UsageReceipt, TokenCount, ReceiptVerification } from '../types/metering.js';
|
|
2
|
-
import { buildSignaturePayload } from './receipt-generator.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Interface for verifying Ed25519 signatures.
|
|
6
|
-
* The actual implementation lives in the identity module (PRD-01).
|
|
7
|
-
*/
|
|
8
|
-
export interface SignatureVerifier {
|
|
9
|
-
/**
|
|
10
|
-
* Verify an Ed25519 signature.
|
|
11
|
-
* @param message - The original signed message (UTF-8 string)
|
|
12
|
-
* @param signature - Hex-encoded signature
|
|
13
|
-
* @param publicKeyHex - Signer's Ed25519 public key (hex)
|
|
14
|
-
* @returns true if signature is valid
|
|
15
|
-
*/
|
|
16
|
-
verify(message: string, signature: string, publicKeyHex: string): boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface VerifierOptions {
|
|
20
|
-
/**
|
|
21
|
-
* Maximum acceptable percentage difference between buyer and seller
|
|
22
|
-
* token estimates before flagging as disputed.
|
|
23
|
-
* Default: 15 (percent)
|
|
24
|
-
*/
|
|
25
|
-
disputeThresholdPercent: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const DEFAULT_OPTIONS: VerifierOptions = {
|
|
29
|
-
disputeThresholdPercent: 15,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Verifies seller-issued usage receipts on the buyer side.
|
|
34
|
-
*/
|
|
35
|
-
export class ReceiptVerifier {
|
|
36
|
-
private readonly signatureVerifier: SignatureVerifier;
|
|
37
|
-
private readonly options: VerifierOptions;
|
|
38
|
-
|
|
39
|
-
constructor(signatureVerifier: SignatureVerifier, options?: Partial<VerifierOptions>) {
|
|
40
|
-
this.signatureVerifier = signatureVerifier;
|
|
41
|
-
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Verify a receipt against the buyer's independent token estimate.
|
|
46
|
-
*
|
|
47
|
-
* Verification steps:
|
|
48
|
-
* 1. Verify the Ed25519 signature using the seller's public key
|
|
49
|
-
* 2. Compare seller's token estimate with buyer's estimate
|
|
50
|
-
* 3. Calculate percentage difference
|
|
51
|
-
* 4. Flag as disputed if difference exceeds threshold
|
|
52
|
-
*
|
|
53
|
-
* @param receipt - The seller's signed receipt
|
|
54
|
-
* @param buyerEstimate - The buyer's independent token estimate
|
|
55
|
-
* @returns ReceiptVerification result
|
|
56
|
-
*/
|
|
57
|
-
verify(receipt: UsageReceipt, buyerEstimate: TokenCount): ReceiptVerification {
|
|
58
|
-
// Step 1: Verify signature
|
|
59
|
-
const payload = buildSignaturePayload(receipt);
|
|
60
|
-
const signatureValid = this.signatureVerifier.verify(
|
|
61
|
-
payload,
|
|
62
|
-
receipt.signature,
|
|
63
|
-
receipt.sellerPeerId
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
// Step 2: Compare token estimates
|
|
67
|
-
const sellerTotal = receipt.tokens.totalTokens;
|
|
68
|
-
const buyerTotal = buyerEstimate.totalTokens;
|
|
69
|
-
const tokenDifference = Math.abs(sellerTotal - buyerTotal);
|
|
70
|
-
|
|
71
|
-
// Step 3: Calculate percentage difference
|
|
72
|
-
const percentageDifference = ReceiptVerifier.calculatePercentageDifference(
|
|
73
|
-
sellerTotal,
|
|
74
|
-
buyerTotal
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
// Step 4: Flag as disputed if signature invalid or difference exceeds threshold
|
|
78
|
-
const disputed = !signatureValid || percentageDifference > this.options.disputeThresholdPercent;
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
receiptId: receipt.receiptId,
|
|
82
|
-
signatureValid,
|
|
83
|
-
buyerTokenEstimate: buyerEstimate,
|
|
84
|
-
sellerTokenEstimate: receipt.tokens,
|
|
85
|
-
tokenDifference,
|
|
86
|
-
percentageDifference,
|
|
87
|
-
disputed,
|
|
88
|
-
verifiedAt: Date.now(),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Calculate the percentage difference between two token counts.
|
|
94
|
-
* Formula: abs(a - b) / max(a, b) * 100
|
|
95
|
-
* Returns 0 if both are 0.
|
|
96
|
-
*/
|
|
97
|
-
static calculatePercentageDifference(a: number, b: number): number {
|
|
98
|
-
const max = Math.max(a, b);
|
|
99
|
-
if (max === 0) return 0;
|
|
100
|
-
return (Math.abs(a - b) / max) * 100;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
import type {
|
|
3
|
-
ProviderType,
|
|
4
|
-
MeteringEvent,
|
|
5
|
-
UsageReceipt,
|
|
6
|
-
ReceiptVerification,
|
|
7
|
-
SessionMetrics,
|
|
8
|
-
} from '../types/metering.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Tracks metering events and receipts for a session,
|
|
12
|
-
* computing running aggregates.
|
|
13
|
-
*
|
|
14
|
-
* Emits:
|
|
15
|
-
* - 'event-recorded' (event: MeteringEvent)
|
|
16
|
-
* - 'receipt-recorded' (receipt: UsageReceipt, verification: ReceiptVerification)
|
|
17
|
-
* - 'dispute-detected' (receiptId: string, percentageDifference: number)
|
|
18
|
-
* - 'session-ended' (metrics: SessionMetrics)
|
|
19
|
-
*/
|
|
20
|
-
export class SessionTracker extends EventEmitter {
|
|
21
|
-
private readonly sessionId: string;
|
|
22
|
-
private readonly sellerPeerId: string;
|
|
23
|
-
private readonly buyerPeerId: string;
|
|
24
|
-
private readonly provider: ProviderType;
|
|
25
|
-
private readonly startedAt: number;
|
|
26
|
-
private endedAt: number | null;
|
|
27
|
-
|
|
28
|
-
private events: MeteringEvent[];
|
|
29
|
-
private receipts: UsageReceipt[];
|
|
30
|
-
private verifications: ReceiptVerification[];
|
|
31
|
-
|
|
32
|
-
private totalTokens: number;
|
|
33
|
-
private totalCostCents: number;
|
|
34
|
-
private totalLatencyMs: number;
|
|
35
|
-
private peerSwitches: number;
|
|
36
|
-
private disputedCount: number;
|
|
37
|
-
private lastPeerId: string;
|
|
38
|
-
|
|
39
|
-
constructor(
|
|
40
|
-
sessionId: string,
|
|
41
|
-
sellerPeerId: string,
|
|
42
|
-
buyerPeerId: string,
|
|
43
|
-
provider: ProviderType
|
|
44
|
-
) {
|
|
45
|
-
super();
|
|
46
|
-
this.sessionId = sessionId;
|
|
47
|
-
this.sellerPeerId = sellerPeerId;
|
|
48
|
-
this.buyerPeerId = buyerPeerId;
|
|
49
|
-
this.provider = provider;
|
|
50
|
-
this.startedAt = Date.now();
|
|
51
|
-
this.endedAt = null;
|
|
52
|
-
|
|
53
|
-
this.events = [];
|
|
54
|
-
this.receipts = [];
|
|
55
|
-
this.verifications = [];
|
|
56
|
-
|
|
57
|
-
this.totalTokens = 0;
|
|
58
|
-
this.totalCostCents = 0;
|
|
59
|
-
this.totalLatencyMs = 0;
|
|
60
|
-
this.peerSwitches = 0;
|
|
61
|
-
this.disputedCount = 0;
|
|
62
|
-
this.lastPeerId = sellerPeerId;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Record a metering event (one request/response cycle).
|
|
67
|
-
*/
|
|
68
|
-
recordEvent(event: MeteringEvent): void {
|
|
69
|
-
this.events.push(event);
|
|
70
|
-
this.totalTokens += event.tokens.totalTokens;
|
|
71
|
-
this.totalLatencyMs += event.latencyMs;
|
|
72
|
-
this.emit('event-recorded', event);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Record a receipt and its verification result.
|
|
77
|
-
*/
|
|
78
|
-
recordReceipt(receipt: UsageReceipt, verification: ReceiptVerification): void {
|
|
79
|
-
this.receipts.push(receipt);
|
|
80
|
-
this.verifications.push(verification);
|
|
81
|
-
this.totalCostCents += receipt.costCents;
|
|
82
|
-
|
|
83
|
-
if (verification.disputed) {
|
|
84
|
-
this.disputedCount++;
|
|
85
|
-
this.emit('dispute-detected', receipt.receiptId, verification.percentageDifference);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.emit('receipt-recorded', receipt, verification);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Record a peer switch (failover to a different seller).
|
|
93
|
-
*/
|
|
94
|
-
recordPeerSwitch(newPeerId: string): void {
|
|
95
|
-
if (newPeerId !== this.lastPeerId) {
|
|
96
|
-
this.peerSwitches++;
|
|
97
|
-
this.lastPeerId = newPeerId;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* End the session and return final metrics.
|
|
103
|
-
*/
|
|
104
|
-
endSession(): SessionMetrics {
|
|
105
|
-
this.endedAt = Date.now();
|
|
106
|
-
const metrics = this.getMetrics();
|
|
107
|
-
this.emit('session-ended', metrics);
|
|
108
|
-
return metrics;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Get current running metrics (session may still be active).
|
|
113
|
-
*/
|
|
114
|
-
getMetrics(): SessionMetrics {
|
|
115
|
-
const totalRequests = this.events.length;
|
|
116
|
-
return {
|
|
117
|
-
sessionId: this.sessionId,
|
|
118
|
-
sellerPeerId: this.sellerPeerId,
|
|
119
|
-
buyerPeerId: this.buyerPeerId,
|
|
120
|
-
provider: this.provider,
|
|
121
|
-
startedAt: this.startedAt,
|
|
122
|
-
endedAt: this.endedAt,
|
|
123
|
-
totalRequests,
|
|
124
|
-
totalTokens: this.totalTokens,
|
|
125
|
-
totalCostCents: this.totalCostCents,
|
|
126
|
-
avgLatencyMs: totalRequests > 0 ? this.totalLatencyMs / totalRequests : 0,
|
|
127
|
-
peerSwitches: this.peerSwitches,
|
|
128
|
-
disputedReceipts: this.disputedCount,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get all events in this session.
|
|
134
|
-
*/
|
|
135
|
-
getEvents(): MeteringEvent[] {
|
|
136
|
-
return [...this.events];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get all receipts in this session.
|
|
141
|
-
*/
|
|
142
|
-
getReceipts(): UsageReceipt[] {
|
|
143
|
-
return [...this.receipts];
|
|
144
|
-
}
|
|
145
|
-
}
|