@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.
Files changed (130) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/interfaces/seller-provider.d.ts +13 -1
  6. package/dist/interfaces/seller-provider.d.ts.map +1 -1
  7. package/dist/node.d.ts +13 -3
  8. package/dist/node.d.ts.map +1 -1
  9. package/dist/node.js +123 -15
  10. package/dist/node.js.map +1 -1
  11. package/dist/proxy/proxy-mux.d.ts +3 -1
  12. package/dist/proxy/proxy-mux.d.ts.map +1 -1
  13. package/dist/proxy/proxy-mux.js +9 -5
  14. package/dist/proxy/proxy-mux.js.map +1 -1
  15. package/dist/types/http.d.ts +1 -0
  16. package/dist/types/http.d.ts.map +1 -1
  17. package/dist/types/http.js +1 -1
  18. package/dist/types/http.js.map +1 -1
  19. package/package.json +14 -10
  20. package/contracts/AntseedEscrow.sol +0 -310
  21. package/contracts/MockUSDC.sol +0 -64
  22. package/contracts/README.md +0 -102
  23. package/src/config/encryption.test.ts +0 -49
  24. package/src/config/encryption.ts +0 -53
  25. package/src/config/plugin-config-manager.test.ts +0 -92
  26. package/src/config/plugin-config-manager.ts +0 -153
  27. package/src/config/plugin-loader.ts +0 -90
  28. package/src/discovery/announcer.ts +0 -169
  29. package/src/discovery/bootstrap.ts +0 -57
  30. package/src/discovery/default-metadata-resolver.ts +0 -18
  31. package/src/discovery/dht-health.ts +0 -136
  32. package/src/discovery/dht-node.ts +0 -191
  33. package/src/discovery/http-metadata-resolver.ts +0 -47
  34. package/src/discovery/index.ts +0 -15
  35. package/src/discovery/metadata-codec.ts +0 -453
  36. package/src/discovery/metadata-resolver.ts +0 -7
  37. package/src/discovery/metadata-server.ts +0 -73
  38. package/src/discovery/metadata-validator.ts +0 -172
  39. package/src/discovery/peer-lookup.ts +0 -122
  40. package/src/discovery/peer-metadata.ts +0 -34
  41. package/src/discovery/peer-selector.ts +0 -134
  42. package/src/discovery/profile-manager.ts +0 -131
  43. package/src/discovery/profile-search.ts +0 -100
  44. package/src/discovery/reputation-verifier.ts +0 -54
  45. package/src/index.ts +0 -61
  46. package/src/interfaces/buyer-router.ts +0 -21
  47. package/src/interfaces/plugin.ts +0 -36
  48. package/src/interfaces/seller-provider.ts +0 -81
  49. package/src/metering/index.ts +0 -6
  50. package/src/metering/receipt-generator.ts +0 -105
  51. package/src/metering/receipt-verifier.ts +0 -102
  52. package/src/metering/session-tracker.ts +0 -145
  53. package/src/metering/storage.ts +0 -600
  54. package/src/metering/token-counter.ts +0 -127
  55. package/src/metering/usage-aggregator.ts +0 -236
  56. package/src/node.ts +0 -1698
  57. package/src/p2p/connection-auth.ts +0 -152
  58. package/src/p2p/connection-manager.ts +0 -916
  59. package/src/p2p/handshake.ts +0 -162
  60. package/src/p2p/ice-config.ts +0 -59
  61. package/src/p2p/identity.ts +0 -110
  62. package/src/p2p/index.ts +0 -11
  63. package/src/p2p/keepalive.ts +0 -118
  64. package/src/p2p/message-protocol.ts +0 -171
  65. package/src/p2p/nat-traversal.ts +0 -169
  66. package/src/p2p/payment-codec.ts +0 -165
  67. package/src/p2p/payment-mux.ts +0 -153
  68. package/src/p2p/reconnect.ts +0 -117
  69. package/src/payments/balance-manager.ts +0 -77
  70. package/src/payments/buyer-payment-manager.ts +0 -414
  71. package/src/payments/disputes.ts +0 -72
  72. package/src/payments/evm/escrow-client.ts +0 -263
  73. package/src/payments/evm/keypair.ts +0 -31
  74. package/src/payments/evm/signatures.ts +0 -103
  75. package/src/payments/evm/wallet.ts +0 -42
  76. package/src/payments/index.ts +0 -50
  77. package/src/payments/settlement.ts +0 -40
  78. package/src/payments/types.ts +0 -79
  79. package/src/proxy/index.ts +0 -3
  80. package/src/proxy/provider-detection.ts +0 -78
  81. package/src/proxy/proxy-mux.ts +0 -173
  82. package/src/proxy/request-codec.ts +0 -294
  83. package/src/reputation/index.ts +0 -6
  84. package/src/reputation/rating-manager.ts +0 -118
  85. package/src/reputation/report-manager.ts +0 -91
  86. package/src/reputation/trust-engine.ts +0 -120
  87. package/src/reputation/trust-score.ts +0 -74
  88. package/src/reputation/uptime-tracker.ts +0 -155
  89. package/src/routing/default-router.ts +0 -75
  90. package/src/types/bittorrent-dht.d.ts +0 -19
  91. package/src/types/buyer.ts +0 -37
  92. package/src/types/capability.ts +0 -34
  93. package/src/types/connection.ts +0 -29
  94. package/src/types/http.ts +0 -20
  95. package/src/types/index.ts +0 -14
  96. package/src/types/metering.ts +0 -175
  97. package/src/types/nat-api.d.ts +0 -29
  98. package/src/types/peer-profile.ts +0 -25
  99. package/src/types/peer.ts +0 -62
  100. package/src/types/plugin-config.ts +0 -31
  101. package/src/types/protocol.ts +0 -162
  102. package/src/types/provider.ts +0 -40
  103. package/src/types/rating.ts +0 -23
  104. package/src/types/report.ts +0 -30
  105. package/src/types/seller.ts +0 -38
  106. package/src/types/staking.ts +0 -23
  107. package/src/utils/debug.ts +0 -30
  108. package/src/utils/hex.ts +0 -14
  109. package/tests/balance-manager.test.ts +0 -156
  110. package/tests/bootstrap.test.ts +0 -108
  111. package/tests/buyer-payment-manager.test.ts +0 -358
  112. package/tests/connection-auth.test.ts +0 -87
  113. package/tests/default-router.test.ts +0 -148
  114. package/tests/evm-keypair.test.ts +0 -173
  115. package/tests/identity.test.ts +0 -133
  116. package/tests/message-protocol.test.ts +0 -212
  117. package/tests/metadata-codec.test.ts +0 -165
  118. package/tests/metadata-validator.test.ts +0 -261
  119. package/tests/metering-storage.test.ts +0 -244
  120. package/tests/payment-codec.test.ts +0 -95
  121. package/tests/payment-mux.test.ts +0 -191
  122. package/tests/peer-selector.test.ts +0 -184
  123. package/tests/provider-detection.test.ts +0 -107
  124. package/tests/proxy-mux-security.test.ts +0 -38
  125. package/tests/receipt.test.ts +0 -215
  126. package/tests/reputation-integration.test.ts +0 -195
  127. package/tests/request-codec.test.ts +0 -144
  128. package/tests/token-counter.test.ts +0 -122
  129. package/tsconfig.json +0 -9
  130. package/vitest.config.ts +0 -7
@@ -1,169 +0,0 @@
1
- import NatAPI from "@silentbot1/nat-api";
2
- import { debugLog, debugWarn } from "../utils/debug.js";
3
-
4
- export interface NatMapping {
5
- /** The internal port that was mapped. */
6
- internalPort: number;
7
- /** The external port on the router (usually same as internal). */
8
- externalPort: number;
9
- /** The external/public IP address. */
10
- externalIp: string;
11
- /** Protocol that was mapped. */
12
- protocol: "TCP" | "UDP";
13
- }
14
-
15
- export interface NatTraversalResult {
16
- /** Whether UPnP/NAT-PMP mapping succeeded. */
17
- success: boolean;
18
- /** External IP if discovered. */
19
- externalIp: string | null;
20
- /** Successfully created mappings. */
21
- mappings: NatMapping[];
22
- }
23
-
24
- /**
25
- * Automatic NAT traversal via UPnP and NAT-PMP.
26
- *
27
- * Requests port forwarding from the router so that inbound connections
28
- * from the internet can reach the seller's signaling port. This is
29
- * transparent to the caller — just call `mapPorts()` after binding
30
- * and `cleanup()` on shutdown.
31
- */
32
- export class NatTraversal {
33
- private _nat: NatAPI | null = null;
34
- private _mappings: NatMapping[] = [];
35
- private _externalIp: string | null = null;
36
- private _destroyed = false;
37
-
38
- /**
39
- * Attempt to map the given ports via UPnP/NAT-PMP.
40
- *
41
- * @param ports - Array of { port, protocol } to map.
42
- * @param timeoutMs - How long to wait before giving up (default 10s).
43
- * @returns Result indicating success and discovered external IP.
44
- */
45
- async mapPorts(
46
- ports: Array<{ port: number; protocol: "TCP" | "UDP" }>,
47
- timeoutMs = 10_000,
48
- ): Promise<NatTraversalResult> {
49
- this._nat = new NatAPI({
50
- enablePMP: true,
51
- enableUPNP: true,
52
- description: "Antseed P2P",
53
- ttl: 7200,
54
- });
55
-
56
- const result: NatTraversalResult = {
57
- success: false,
58
- externalIp: null,
59
- mappings: [],
60
- };
61
-
62
- // Race against timeout
63
- try {
64
- await Promise.race([
65
- this._doMapping(ports, result),
66
- rejectAfter(timeoutMs, "NAT traversal timed out"),
67
- ]);
68
- } catch (err) {
69
- // Timeout or error — return partial result
70
- const msg = err instanceof Error ? err.message : String(err);
71
- debugWarn(`[NAT] ${msg}`);
72
- }
73
-
74
- this._mappings = result.mappings;
75
- this._externalIp = result.externalIp;
76
- result.success = result.mappings.length > 0;
77
-
78
- return result;
79
- }
80
-
81
- private async _doMapping(
82
- ports: Array<{ port: number; protocol: "TCP" | "UDP" }>,
83
- result: NatTraversalResult,
84
- ): Promise<void> {
85
- if (!this._nat) return;
86
-
87
- // Try to get external IP first
88
- try {
89
- const ip = await this._nat.externalIp();
90
- if (ip) {
91
- result.externalIp = ip;
92
- debugLog(`[NAT] External IP: ${ip}`);
93
- }
94
- } catch {
95
- debugWarn("[NAT] Could not determine external IP");
96
- }
97
-
98
- // Map each port
99
- for (const { port, protocol } of ports) {
100
- try {
101
- const mapped = await this._nat.map({
102
- publicPort: port,
103
- privatePort: port,
104
- protocol,
105
- description: `Antseed ${protocol}`,
106
- });
107
-
108
- if (mapped) {
109
- const mapping: NatMapping = {
110
- internalPort: port,
111
- externalPort: port,
112
- externalIp: result.externalIp ?? "",
113
- protocol,
114
- };
115
- result.mappings.push(mapping);
116
- debugLog(`[NAT] Mapped ${protocol} port ${port}`);
117
- } else {
118
- debugWarn(`[NAT] Failed to map ${protocol} port ${port}`);
119
- }
120
- } catch (err) {
121
- const msg = err instanceof Error ? err.message : String(err);
122
- debugWarn(`[NAT] Error mapping ${protocol} port ${port}: ${msg}`);
123
- }
124
- }
125
- }
126
-
127
- /** The external IP discovered during mapping, if any. */
128
- get externalIp(): string | null {
129
- return this._externalIp;
130
- }
131
-
132
- /** All active port mappings. */
133
- get mappings(): readonly NatMapping[] {
134
- return this._mappings;
135
- }
136
-
137
- /** Remove all port mappings and clean up. */
138
- async cleanup(): Promise<void> {
139
- if (this._destroyed || !this._nat) return;
140
- this._destroyed = true;
141
-
142
- for (const m of this._mappings) {
143
- try {
144
- await this._nat.unmap({
145
- publicPort: m.externalPort,
146
- privatePort: m.internalPort,
147
- protocol: m.protocol,
148
- });
149
- } catch {
150
- // Best-effort cleanup
151
- }
152
- }
153
-
154
- try {
155
- await this._nat.destroy();
156
- } catch {
157
- // Best-effort cleanup
158
- }
159
-
160
- this._mappings = [];
161
- this._nat = null;
162
- }
163
- }
164
-
165
- function rejectAfter(ms: number, message: string): Promise<never> {
166
- return new Promise((_, reject) => {
167
- setTimeout(() => reject(new Error(message)), ms);
168
- });
169
- }
@@ -1,165 +0,0 @@
1
- import type {
2
- SessionLockAuthPayload,
3
- SessionLockConfirmPayload,
4
- SessionLockRejectPayload,
5
- SellerReceiptPayload,
6
- BuyerAckPayload,
7
- SessionEndPayload,
8
- TopUpRequestPayload,
9
- TopUpAuthPayload,
10
- DisputeNotifyPayload,
11
- } from '../types/protocol.js';
12
-
13
- const encoder = new TextEncoder();
14
- const decoder = new TextDecoder();
15
-
16
- // --- Validation helpers ---
17
-
18
- function parseJson(data: Uint8Array): Record<string, unknown> {
19
- const raw: unknown = JSON.parse(decoder.decode(data));
20
- if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
21
- throw new Error('Expected JSON object');
22
- }
23
- return raw as Record<string, unknown>;
24
- }
25
-
26
- function requireString(obj: Record<string, unknown>, field: string): string {
27
- const val = obj[field];
28
- if (typeof val !== 'string' || val.length === 0) {
29
- throw new Error(`Missing or invalid string field: ${field}`);
30
- }
31
- return val;
32
- }
33
-
34
- function requireNumber(obj: Record<string, unknown>, field: string): number {
35
- const val = obj[field];
36
- if (typeof val !== 'number' || !Number.isFinite(val)) {
37
- throw new Error(`Missing or invalid number field: ${field}`);
38
- }
39
- return val;
40
- }
41
-
42
- // --- Encoders ---
43
-
44
- export function encodeSessionLockAuth(payload: SessionLockAuthPayload): Uint8Array {
45
- return encoder.encode(JSON.stringify(payload));
46
- }
47
-
48
- export function encodeSessionLockConfirm(payload: SessionLockConfirmPayload): Uint8Array {
49
- return encoder.encode(JSON.stringify(payload));
50
- }
51
-
52
- export function encodeSessionLockReject(payload: SessionLockRejectPayload): Uint8Array {
53
- return encoder.encode(JSON.stringify(payload));
54
- }
55
-
56
- export function encodeSellerReceipt(payload: SellerReceiptPayload): Uint8Array {
57
- return encoder.encode(JSON.stringify(payload));
58
- }
59
-
60
- export function encodeBuyerAck(payload: BuyerAckPayload): Uint8Array {
61
- return encoder.encode(JSON.stringify(payload));
62
- }
63
-
64
- export function encodeSessionEnd(payload: SessionEndPayload): Uint8Array {
65
- return encoder.encode(JSON.stringify(payload));
66
- }
67
-
68
- export function encodeTopUpRequest(payload: TopUpRequestPayload): Uint8Array {
69
- return encoder.encode(JSON.stringify(payload));
70
- }
71
-
72
- export function encodeTopUpAuth(payload: TopUpAuthPayload): Uint8Array {
73
- return encoder.encode(JSON.stringify(payload));
74
- }
75
-
76
- export function encodeDisputeNotify(payload: DisputeNotifyPayload): Uint8Array {
77
- return encoder.encode(JSON.stringify(payload));
78
- }
79
-
80
- // --- Decoders (with runtime validation) ---
81
-
82
- export function decodeSessionLockAuth(data: Uint8Array): SessionLockAuthPayload {
83
- const obj = parseJson(data);
84
- return {
85
- sessionId: requireString(obj, 'sessionId'),
86
- lockedAmount: requireString(obj, 'lockedAmount'),
87
- buyerSig: requireString(obj, 'buyerSig'),
88
- };
89
- }
90
-
91
- export function decodeSessionLockConfirm(data: Uint8Array): SessionLockConfirmPayload {
92
- const obj = parseJson(data);
93
- return {
94
- sessionId: requireString(obj, 'sessionId'),
95
- txSignature: requireString(obj, 'txSignature'),
96
- };
97
- }
98
-
99
- export function decodeSessionLockReject(data: Uint8Array): SessionLockRejectPayload {
100
- const obj = parseJson(data);
101
- return {
102
- sessionId: requireString(obj, 'sessionId'),
103
- reason: requireString(obj, 'reason'),
104
- };
105
- }
106
-
107
- export function decodeSellerReceipt(data: Uint8Array): SellerReceiptPayload {
108
- const obj = parseJson(data);
109
- return {
110
- sessionId: requireString(obj, 'sessionId'),
111
- runningTotal: requireString(obj, 'runningTotal'),
112
- requestCount: requireNumber(obj, 'requestCount'),
113
- responseHash: requireString(obj, 'responseHash'),
114
- sellerSig: requireString(obj, 'sellerSig'),
115
- };
116
- }
117
-
118
- export function decodeBuyerAck(data: Uint8Array): BuyerAckPayload {
119
- const obj = parseJson(data);
120
- return {
121
- sessionId: requireString(obj, 'sessionId'),
122
- runningTotal: requireString(obj, 'runningTotal'),
123
- requestCount: requireNumber(obj, 'requestCount'),
124
- buyerSig: requireString(obj, 'buyerSig'),
125
- };
126
- }
127
-
128
- export function decodeSessionEnd(data: Uint8Array): SessionEndPayload {
129
- const obj = parseJson(data);
130
- return {
131
- sessionId: requireString(obj, 'sessionId'),
132
- runningTotal: requireString(obj, 'runningTotal'),
133
- requestCount: requireNumber(obj, 'requestCount'),
134
- score: requireNumber(obj, 'score'),
135
- buyerSig: requireString(obj, 'buyerSig'),
136
- };
137
- }
138
-
139
- export function decodeTopUpRequest(data: Uint8Array): TopUpRequestPayload {
140
- const obj = parseJson(data);
141
- return {
142
- sessionId: requireString(obj, 'sessionId'),
143
- additionalAmount: requireString(obj, 'additionalAmount'),
144
- currentRunningTotal: requireString(obj, 'currentRunningTotal'),
145
- currentLockedAmount: requireString(obj, 'currentLockedAmount'),
146
- };
147
- }
148
-
149
- export function decodeTopUpAuth(data: Uint8Array): TopUpAuthPayload {
150
- const obj = parseJson(data);
151
- return {
152
- sessionId: requireString(obj, 'sessionId'),
153
- additionalAmount: requireString(obj, 'additionalAmount'),
154
- buyerSig: requireString(obj, 'buyerSig'),
155
- };
156
- }
157
-
158
- export function decodeDisputeNotify(data: Uint8Array): DisputeNotifyPayload {
159
- const obj = parseJson(data);
160
- return {
161
- sessionId: requireString(obj, 'sessionId'),
162
- reason: requireString(obj, 'reason'),
163
- txSignature: requireString(obj, 'txSignature'),
164
- };
165
- }
@@ -1,153 +0,0 @@
1
- import type { PeerConnection } from './connection-manager.js';
2
- import { MessageType } from '../types/protocol.js';
3
- import type {
4
- SessionLockAuthPayload,
5
- SessionLockConfirmPayload,
6
- SessionLockRejectPayload,
7
- SellerReceiptPayload,
8
- BuyerAckPayload,
9
- SessionEndPayload,
10
- TopUpRequestPayload,
11
- TopUpAuthPayload,
12
- DisputeNotifyPayload,
13
- } from '../types/protocol.js';
14
- import { encodeFrame } from './message-protocol.js';
15
- import type { FramedMessage } from '../types/protocol.js';
16
- import * as codec from './payment-codec.js';
17
-
18
- export type PaymentMessageHandler<T> = (payload: T) => void | Promise<void>;
19
-
20
- /**
21
- * Multiplexes bilateral payment messages over a PeerConnection.
22
- * Register handlers for each message type, then call handleFrame()
23
- * when a payment-range frame arrives.
24
- */
25
- export class PaymentMux {
26
- private _connection: PeerConnection;
27
- private _messageIdCounter = 0;
28
-
29
- // Handler registrations
30
- private _onSessionLockAuth?: PaymentMessageHandler<SessionLockAuthPayload>;
31
- private _onSessionLockConfirm?: PaymentMessageHandler<SessionLockConfirmPayload>;
32
- private _onSessionLockReject?: PaymentMessageHandler<SessionLockRejectPayload>;
33
- private _onSellerReceipt?: PaymentMessageHandler<SellerReceiptPayload>;
34
- private _onBuyerAck?: PaymentMessageHandler<BuyerAckPayload>;
35
- private _onSessionEnd?: PaymentMessageHandler<SessionEndPayload>;
36
- private _onTopUpRequest?: PaymentMessageHandler<TopUpRequestPayload>;
37
- private _onTopUpAuth?: PaymentMessageHandler<TopUpAuthPayload>;
38
- private _onDisputeNotify?: PaymentMessageHandler<DisputeNotifyPayload>;
39
-
40
- constructor(connection: PeerConnection) {
41
- this._connection = connection;
42
- }
43
-
44
- // --- Handler registration ---
45
- onSessionLockAuth(handler: PaymentMessageHandler<SessionLockAuthPayload>): void {
46
- this._onSessionLockAuth = handler;
47
- }
48
- onSessionLockConfirm(handler: PaymentMessageHandler<SessionLockConfirmPayload>): void {
49
- this._onSessionLockConfirm = handler;
50
- }
51
- onSessionLockReject(handler: PaymentMessageHandler<SessionLockRejectPayload>): void {
52
- this._onSessionLockReject = handler;
53
- }
54
- onSellerReceipt(handler: PaymentMessageHandler<SellerReceiptPayload>): void {
55
- this._onSellerReceipt = handler;
56
- }
57
- onBuyerAck(handler: PaymentMessageHandler<BuyerAckPayload>): void {
58
- this._onBuyerAck = handler;
59
- }
60
- onSessionEnd(handler: PaymentMessageHandler<SessionEndPayload>): void {
61
- this._onSessionEnd = handler;
62
- }
63
- onTopUpRequest(handler: PaymentMessageHandler<TopUpRequestPayload>): void {
64
- this._onTopUpRequest = handler;
65
- }
66
- onTopUpAuth(handler: PaymentMessageHandler<TopUpAuthPayload>): void {
67
- this._onTopUpAuth = handler;
68
- }
69
- onDisputeNotify(handler: PaymentMessageHandler<DisputeNotifyPayload>): void {
70
- this._onDisputeNotify = handler;
71
- }
72
-
73
- // --- Sending ---
74
- sendSessionLockAuth(payload: SessionLockAuthPayload): void {
75
- this._send(MessageType.SessionLockAuth, codec.encodeSessionLockAuth(payload));
76
- }
77
- sendSessionLockConfirm(payload: SessionLockConfirmPayload): void {
78
- this._send(MessageType.SessionLockConfirm, codec.encodeSessionLockConfirm(payload));
79
- }
80
- sendSessionLockReject(payload: SessionLockRejectPayload): void {
81
- this._send(MessageType.SessionLockReject, codec.encodeSessionLockReject(payload));
82
- }
83
- sendSellerReceipt(payload: SellerReceiptPayload): void {
84
- this._send(MessageType.SellerReceipt, codec.encodeSellerReceipt(payload));
85
- }
86
- sendBuyerAck(payload: BuyerAckPayload): void {
87
- this._send(MessageType.BuyerAck, codec.encodeBuyerAck(payload));
88
- }
89
- sendSessionEnd(payload: SessionEndPayload): void {
90
- this._send(MessageType.SessionEnd, codec.encodeSessionEnd(payload));
91
- }
92
- sendTopUpRequest(payload: TopUpRequestPayload): void {
93
- this._send(MessageType.TopUpRequest, codec.encodeTopUpRequest(payload));
94
- }
95
- sendTopUpAuth(payload: TopUpAuthPayload): void {
96
- this._send(MessageType.TopUpAuth, codec.encodeTopUpAuth(payload));
97
- }
98
- sendDisputeNotify(payload: DisputeNotifyPayload): void {
99
- this._send(MessageType.DisputeNotify, codec.encodeDisputeNotify(payload));
100
- }
101
-
102
- // --- Receiving ---
103
- /**
104
- * Returns true if this frame is a payment message and was handled.
105
- */
106
- async handleFrame(frame: FramedMessage): Promise<boolean> {
107
- switch (frame.type) {
108
- case MessageType.SessionLockAuth:
109
- await this._onSessionLockAuth?.(codec.decodeSessionLockAuth(frame.payload));
110
- return true;
111
- case MessageType.SessionLockConfirm:
112
- await this._onSessionLockConfirm?.(codec.decodeSessionLockConfirm(frame.payload));
113
- return true;
114
- case MessageType.SessionLockReject:
115
- await this._onSessionLockReject?.(codec.decodeSessionLockReject(frame.payload));
116
- return true;
117
- case MessageType.SellerReceipt:
118
- await this._onSellerReceipt?.(codec.decodeSellerReceipt(frame.payload));
119
- return true;
120
- case MessageType.BuyerAck:
121
- await this._onBuyerAck?.(codec.decodeBuyerAck(frame.payload));
122
- return true;
123
- case MessageType.SessionEnd:
124
- await this._onSessionEnd?.(codec.decodeSessionEnd(frame.payload));
125
- return true;
126
- case MessageType.TopUpRequest:
127
- await this._onTopUpRequest?.(codec.decodeTopUpRequest(frame.payload));
128
- return true;
129
- case MessageType.TopUpAuth:
130
- await this._onTopUpAuth?.(codec.decodeTopUpAuth(frame.payload));
131
- return true;
132
- case MessageType.DisputeNotify:
133
- await this._onDisputeNotify?.(codec.decodeDisputeNotify(frame.payload));
134
- return true;
135
- default:
136
- return false;
137
- }
138
- }
139
-
140
- /** Check if a message type is in the payment range (0x50-0x5F). */
141
- static isPaymentMessage(type: number): boolean {
142
- return type >= 0x50 && type <= 0x5f;
143
- }
144
-
145
- private _send(type: MessageType, payload: Uint8Array): void {
146
- const frame = encodeFrame({
147
- type,
148
- messageId: this._messageIdCounter++ & 0xffffffff,
149
- payload,
150
- });
151
- this._connection.send(frame);
152
- }
153
- }
@@ -1,117 +0,0 @@
1
- /** Configuration for the reconnection strategy. */
2
- export interface ReconnectConfig {
3
- /** Base delay in milliseconds before the first reconnect attempt. */
4
- baseDelayMs?: number;
5
- /** Maximum delay in milliseconds between reconnect attempts. */
6
- maxDelayMs?: number;
7
- /** Maximum number of reconnect attempts before giving up. */
8
- maxAttempts?: number;
9
- /** Jitter factor (0-1) to randomize the delay. */
10
- jitterFactor?: number;
11
- }
12
-
13
- const DEFAULT_BASE_DELAY_MS = 1_000;
14
- const DEFAULT_MAX_DELAY_MS = 30_000;
15
- const DEFAULT_MAX_ATTEMPTS = 5;
16
- const DEFAULT_JITTER_FACTOR = 0.3;
17
-
18
- export interface ReconnectCallbacks {
19
- /** Called when a reconnect attempt should be made. */
20
- onReconnect: (attempt: number) => Promise<boolean>;
21
- /** Called when all attempts are exhausted. */
22
- onGiveUp: (totalAttempts: number) => void;
23
- /** Called when reconnection succeeds. */
24
- onSuccess: (attempt: number) => void;
25
- }
26
-
27
- /**
28
- * Manages reconnection with exponential backoff and jitter.
29
- *
30
- * Delay formula: min(baseDelay * 2^attempt + jitter, maxDelay)
31
- */
32
- export class ReconnectManager {
33
- private _baseDelay: number;
34
- private _maxDelay: number;
35
- private _maxAttempts: number;
36
- private _jitterFactor: number;
37
- private _attempt = 0;
38
- private _callbacks: ReconnectCallbacks;
39
- private _timeoutHandle: ReturnType<typeof setTimeout> | null = null;
40
- private _active = false;
41
-
42
- constructor(callbacks: ReconnectCallbacks, config?: ReconnectConfig) {
43
- this._callbacks = callbacks;
44
- this._baseDelay = config?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
45
- this._maxDelay = config?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
46
- this._maxAttempts = config?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
47
- this._jitterFactor = config?.jitterFactor ?? DEFAULT_JITTER_FACTOR;
48
- }
49
-
50
- get attempt(): number {
51
- return this._attempt;
52
- }
53
-
54
- get isActive(): boolean {
55
- return this._active;
56
- }
57
-
58
- /** Calculate delay for the current attempt with exponential backoff + jitter. */
59
- calculateDelay(attempt: number): number {
60
- const exponentialDelay = this._baseDelay * Math.pow(2, attempt);
61
- const jitter = exponentialDelay * this._jitterFactor * Math.random();
62
- return Math.min(exponentialDelay + jitter, this._maxDelay);
63
- }
64
-
65
- /** Start the reconnection process. */
66
- start(): void {
67
- if (this._active) return;
68
- this._active = true;
69
- this._attempt = 0;
70
- this._scheduleAttempt();
71
- }
72
-
73
- /** Stop the reconnection process. */
74
- stop(): void {
75
- this._active = false;
76
- if (this._timeoutHandle) {
77
- clearTimeout(this._timeoutHandle);
78
- this._timeoutHandle = null;
79
- }
80
- }
81
-
82
- /** Reset the attempt counter (e.g., after a successful connection). */
83
- reset(): void {
84
- this._attempt = 0;
85
- this.stop();
86
- }
87
-
88
- /** Schedule the next reconnect attempt. */
89
- private _scheduleAttempt(): void {
90
- if (!this._active) return;
91
-
92
- if (this._attempt >= this._maxAttempts) {
93
- this._active = false;
94
- this._callbacks.onGiveUp(this._attempt);
95
- return;
96
- }
97
-
98
- const delay = this.calculateDelay(this._attempt);
99
-
100
- this._timeoutHandle = setTimeout(async () => {
101
- if (!this._active) return;
102
-
103
- this._attempt++;
104
- try {
105
- const success = await this._callbacks.onReconnect(this._attempt);
106
- if (success) {
107
- this._active = false;
108
- this._callbacks.onSuccess(this._attempt);
109
- } else {
110
- this._scheduleAttempt();
111
- }
112
- } catch {
113
- this._scheduleAttempt();
114
- }
115
- }, delay);
116
- }
117
- }
@@ -1,77 +0,0 @@
1
- import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
- import { join } from 'node:path';
3
- import type { WalletInfo, Transaction, TransactionType } from './types.js';
4
-
5
- export interface UnifiedBalance {
6
- cryptoUSDC: number;
7
- inEscrowUSDC: number;
8
- totalUSD: number;
9
- }
10
-
11
- export class BalanceManager {
12
- private transactions: Transaction[] = [];
13
-
14
- getBalance(
15
- walletInfo: WalletInfo | null,
16
- inEscrowUSDC: number,
17
- ): UnifiedBalance {
18
- const cryptoUSDC = walletInfo ? parseFloat(walletInfo.balanceUSDC) : 0;
19
- const totalUSD = cryptoUSDC + inEscrowUSDC;
20
-
21
- return {
22
- cryptoUSDC,
23
- inEscrowUSDC,
24
- totalUSD,
25
- };
26
- }
27
-
28
- recordTransaction(tx: Transaction): void {
29
- this.transactions.push(tx);
30
- }
31
-
32
- getTransactionHistory(
33
- filter?: TransactionType,
34
- limit?: number,
35
- offset?: number,
36
- ): Transaction[] {
37
- let result = this.transactions;
38
-
39
- if (filter) {
40
- result = result.filter((tx) => tx.type === filter);
41
- }
42
-
43
- const start = offset ?? 0;
44
- const end = limit !== undefined ? start + limit : undefined;
45
- return result.slice(start, end);
46
- }
47
-
48
- getTotalEarnings(since?: number): number {
49
- return this.transactions
50
- .filter((tx) => tx.type === 'escrow_release')
51
- .filter((tx) => (since !== undefined ? tx.timestamp >= since : true))
52
- .reduce((sum, tx) => sum + tx.amountUSD, 0);
53
- }
54
-
55
- getTotalSpending(since?: number): number {
56
- return this.transactions
57
- .filter((tx) => tx.type === 'escrow_lock')
58
- .filter((tx) => (since !== undefined ? tx.timestamp >= since : true))
59
- .reduce((sum, tx) => sum + tx.amountUSD, 0);
60
- }
61
-
62
- async save(configDir: string): Promise<void> {
63
- await mkdir(configDir, { recursive: true });
64
- const filePath = join(configDir, 'transactions.json');
65
- await writeFile(filePath, JSON.stringify(this.transactions, null, 2), 'utf-8');
66
- }
67
-
68
- async load(configDir: string): Promise<void> {
69
- const filePath = join(configDir, 'transactions.json');
70
- try {
71
- const data = await readFile(filePath, 'utf-8');
72
- this.transactions = JSON.parse(data) as Transaction[];
73
- } catch {
74
- this.transactions = [];
75
- }
76
- }
77
- }