lovewebconnection 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.env.example +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1915 -2
  4. package/dist/alert-queue.d.ts +72 -0
  5. package/dist/alert-queue.js +155 -0
  6. package/dist/alert-store.d.ts +29 -0
  7. package/dist/alert-store.js +75 -0
  8. package/dist/balances.d.ts +221 -0
  9. package/dist/balances.js +1232 -0
  10. package/dist/cache.d.ts +37 -0
  11. package/dist/cache.js +128 -0
  12. package/dist/call.d.ts +46 -0
  13. package/dist/call.js +377 -0
  14. package/dist/chain.d.ts +97 -0
  15. package/dist/chain.js +419 -0
  16. package/dist/cli.d.ts +2 -0
  17. package/dist/cli.js +1011 -0
  18. package/dist/compare-history.d.ts +82 -0
  19. package/dist/compare-history.js +340 -0
  20. package/dist/compare.d.ts +98 -0
  21. package/dist/compare.js +492 -0
  22. package/dist/contract.d.ts +107 -0
  23. package/dist/contract.js +162 -0
  24. package/dist/default-abi.d.ts +53 -0
  25. package/dist/default-abi.js +85 -0
  26. package/dist/history.d.ts +83 -0
  27. package/dist/history.js +422 -0
  28. package/dist/index.d.ts +54 -0
  29. package/dist/index.js +27 -0
  30. package/dist/market-page.d.ts +8 -0
  31. package/dist/market-page.js +554 -0
  32. package/dist/market-server.d.ts +46 -0
  33. package/dist/market-server.js +473 -0
  34. package/dist/market.d.ts +323 -0
  35. package/dist/market.js +835 -0
  36. package/dist/metadata-cache.d.ts +72 -0
  37. package/dist/metadata-cache.js +197 -0
  38. package/dist/metrics.d.ts +64 -0
  39. package/dist/metrics.js +138 -0
  40. package/dist/plot.d.ts +60 -0
  41. package/dist/plot.js +317 -0
  42. package/dist/presets-history.d.ts +372 -0
  43. package/dist/presets-history.js +1243 -0
  44. package/dist/presets-summary.d.ts +17 -0
  45. package/dist/presets-summary.js +55 -0
  46. package/dist/presets.d.ts +59 -0
  47. package/dist/presets.js +181 -0
  48. package/dist/prices.d.ts +63 -0
  49. package/dist/prices.js +154 -0
  50. package/dist/rotate.d.ts +19 -0
  51. package/dist/rotate.js +34 -0
  52. package/dist/scan.d.ts +81 -0
  53. package/dist/scan.js +501 -0
  54. package/dist/sessions.d.ts +104 -0
  55. package/dist/sessions.js +515 -0
  56. package/dist/signatures.d.ts +13 -0
  57. package/dist/signatures.js +43 -0
  58. package/dist/tokenfile.d.ts +50 -0
  59. package/dist/tokenfile.js +218 -0
  60. package/dist/views.d.ts +63 -0
  61. package/dist/views.js +415 -0
  62. package/dist/watch.d.ts +306 -0
  63. package/dist/watch.js +1121 -0
  64. package/dist/webhook.d.ts +17 -0
  65. package/dist/webhook.js +35 -0
  66. package/examples/erc20.abi.json +57 -0
  67. package/examples/xlayer.tokens.json +4 -0
  68. package/package.json +77 -4
@@ -0,0 +1,306 @@
1
+ import { type Address, type PublicClient } from "viem";
2
+ import { type BalancesReport, type ChunkProgress, type ChunkStatus } from "./balances.ts";
3
+ import type { ChainConfig } from "./chain.ts";
4
+ import { type SessionMetrics, type WatchMetrics } from "./metrics.ts";
5
+ import { type PriceBook } from "./prices.ts";
6
+ export interface WatchOptions {
7
+ /** Delay between polls. */
8
+ intervalMs: number;
9
+ /** How long the head may stay unchanged before a stall is reported. */
10
+ stallAfterSeconds: number;
11
+ /** Stop after this many successful samples; 0 runs until interrupted. */
12
+ maxSamples: number;
13
+ /** Percentage above the rolling gas baseline that counts as a surge. */
14
+ gasSurgePercent: number;
15
+ /** Rolling window size for latency and block-time statistics. */
16
+ windowSize: number;
17
+ /** Emit a rolling metrics line every n samples; 0 disables it. */
18
+ reportEvery: number;
19
+ /** Append every event to this file as one JSON object per line; null disables it. */
20
+ logPath: string | null;
21
+ /** Rotate the log to <path>.1 when it would grow past this many bytes; 0 disables it. */
22
+ logMaxBytes: number;
23
+ /** Re-launch in the background, logging to logPath, then exit. */
24
+ detach: boolean;
25
+ /** Alert when rolling p95 latency exceeds this many ms; null disables it. */
26
+ alertLatencyMs: number | null;
27
+ /** Alert when rolling median block time exceeds this many seconds; null disables it. */
28
+ alertBlockTimeSeconds: number | null;
29
+ /** Alert when a portfolio asset moves more than this percent between samples; null disables it. */
30
+ alertBalancePercent: number | null;
31
+ /** POST alert events here; null only prints and logs them. */
32
+ webhookUrl: string | null;
33
+ /** Authorization header sent with alert POSTs; null sends none. */
34
+ alertAuthHeader: string | null;
35
+ /** Durable alert queue file; null derives one from the log path. */
36
+ alertQueuePath: string | null;
37
+ /** Where alertAuthHeader came from; only used to word validation errors. */
38
+ /** Owner whose portfolio is read; null disables portfolio sampling. */
39
+ owner: Address | null;
40
+ /** Portfolio tokens, loaded from --tokens-file. */
41
+ tokens: Address[];
42
+ /** Lowercased token address → label from the token list file. */
43
+ labels: Map<string, string>;
44
+ /** Sample the portfolio every n polls. */
45
+ portfolioEvery: number;
46
+ /**
47
+ * Tokens per Multicall3 request when reading the portfolio; null uses
48
+ * readBalances' automatic 12 uncached / 24 fully cached chunking.
49
+ */
50
+ batchSize: number | null;
51
+ /** Fixed sub-call cap per portfolio request; null uses batchSize. */
52
+ maxSubCalls: number | null;
53
+ /** Print one line per portfolio Multicall3 chunk to stderr. */
54
+ verbose: boolean;
55
+ /** Value the portfolio in USD using DefiLlama prices. */
56
+ usd: boolean;
57
+ }
58
+ export declare const DEFAULT_WATCH_OPTIONS: WatchOptions;
59
+ export declare class WatchArgError extends Error {
60
+ constructor(message: string);
61
+ }
62
+ /** `512kb`, `10mb`, `1gb`, or a bare number of megabytes. */
63
+ export declare function parseLogSize(raw: string): number;
64
+ export declare function parseWatchArgs(argv: string[], env?: Record<string, string | undefined>): WatchOptions;
65
+ export interface PortfolioHolding {
66
+ address: Address;
67
+ symbol: string;
68
+ label: string | null;
69
+ decimals: number | null;
70
+ balance: bigint | null;
71
+ /** Change since the previous portfolio sample; null for the first one. */
72
+ delta: bigint | null;
73
+ /** USD value at this sample's prices; null when the asset could not be priced. */
74
+ usd: number | null;
75
+ }
76
+ export interface PortfolioNative {
77
+ symbol: string;
78
+ decimals: number;
79
+ balance: bigint;
80
+ delta: bigint | null;
81
+ usd: number | null;
82
+ }
83
+ export type WatchEvent = {
84
+ type: "advance";
85
+ at: number;
86
+ blockNumber: bigint;
87
+ delta: bigint;
88
+ gasPriceWei: bigint | null;
89
+ latencyMs: number;
90
+ } | {
91
+ type: "hold";
92
+ at: number;
93
+ blockNumber: bigint;
94
+ staleSeconds: number;
95
+ gasPriceWei: bigint | null;
96
+ latencyMs: number;
97
+ } | {
98
+ type: "stall";
99
+ at: number;
100
+ blockNumber: bigint;
101
+ staleSeconds: number;
102
+ } | {
103
+ type: "recovered";
104
+ at: number;
105
+ from: bigint;
106
+ to: bigint;
107
+ stalledForSeconds: number;
108
+ } | {
109
+ type: "chain-drift";
110
+ at: number;
111
+ expected: number;
112
+ previous: number | null;
113
+ actual: number;
114
+ } | {
115
+ type: "gas-surge";
116
+ at: number;
117
+ gasPriceWei: bigint;
118
+ baselineWei: bigint;
119
+ increasePercent: number;
120
+ } | {
121
+ type: "gas-normal";
122
+ at: number;
123
+ gasPriceWei: bigint;
124
+ baselineWei: bigint;
125
+ } | {
126
+ type: "alert";
127
+ at: number;
128
+ metric: "latency" | "block-time";
129
+ direction: "breach" | "clear";
130
+ value: number;
131
+ threshold: number;
132
+ /** Rolling metrics snapshot that triggered this alert. */
133
+ metrics: WatchMetrics;
134
+ /** Whole-session totals at the moment of the alert. */
135
+ cumulative: SessionMetrics;
136
+ } | {
137
+ type: "balance-alert";
138
+ at: number;
139
+ asset: "native" | "token";
140
+ /** Token address, or null for the native balance. */
141
+ address: Address | null;
142
+ symbol: string;
143
+ label: string | null;
144
+ decimals: number | null;
145
+ previous: bigint;
146
+ balance: bigint;
147
+ delta: bigint;
148
+ /** Percent moved, rounded; null when the previous balance was zero. */
149
+ changePercent: number | null;
150
+ thresholdPercent: number;
151
+ } | {
152
+ type: "portfolio";
153
+ at: number;
154
+ blockNumber: bigint | null;
155
+ /** Tokens per Multicall3 request for this sample; null when it failed. */
156
+ batchSize: number | null;
157
+ /** Multicall3 chunks used by this sample; null when it failed. */
158
+ chunkCount: number | null;
159
+ native: PortfolioNative | null;
160
+ tokens: PortfolioHolding[];
161
+ /** Sum of the priced holdings, or null when nothing could be priced. */
162
+ usdTotal: number | null;
163
+ /** Why prices were unavailable; null when they were not needed or worked. */
164
+ priceError: string | null;
165
+ error: string | null;
166
+ } | {
167
+ type: "chunk-recovery";
168
+ at: number;
169
+ /** Portfolio owner whose chunks were read. */
170
+ owner: Address;
171
+ /** 1-based position of the chunk that needed a retry, and the chunk count. */
172
+ chunk: number;
173
+ chunks: number;
174
+ /** Tokens assigned to the chunk. */
175
+ tokens: number;
176
+ status: ChunkStatus;
177
+ /** Why the chunk's first Multicall3 request failed; null when unknown. */
178
+ error: string | null;
179
+ /** Tokens from the chunk that had to be re-read individually. */
180
+ individual: Address[];
181
+ } | {
182
+ type: "metrics";
183
+ at: number;
184
+ /** Rolling window snapshot. */
185
+ metrics: WatchMetrics;
186
+ /** Whole-session totals at the same moment. */
187
+ cumulative: SessionMetrics;
188
+ } | {
189
+ type: "error";
190
+ at: number;
191
+ message: string;
192
+ };
193
+ export interface WatchTrackerState {
194
+ lastBlock: bigint | null;
195
+ lastChainId: number | null;
196
+ lastAdvanceAt: number;
197
+ stalledSince: number | null;
198
+ gasHistory: bigint[];
199
+ gasSurge: boolean;
200
+ }
201
+ export interface WatchSample {
202
+ at: number;
203
+ blockNumber: bigint;
204
+ chainId: number;
205
+ gasPriceWei: bigint | null;
206
+ latencyMs: number;
207
+ }
208
+ export declare function createTracker(): WatchTrackerState;
209
+ /**
210
+ * Pure state machine: given the previous state and a fresh sample, decide which
211
+ * events happened. Chain drift is reported when the observed id differs from the
212
+ * configured one and from the previous observation. Gas surges compare the
213
+ * current price against the median of the last readings, with hysteresis so a
214
+ * price hovering at the threshold does not flap.
215
+ */
216
+ export declare function evaluateSample(state: WatchTrackerState, sample: WatchSample, options: Pick<WatchOptions, "stallAfterSeconds" | "gasSurgePercent">, expectedChainId: number): {
217
+ state: WatchTrackerState;
218
+ events: WatchEvent[];
219
+ };
220
+ export interface AlertState {
221
+ latencyBreaching: boolean;
222
+ blockTimeBreaching: boolean;
223
+ }
224
+ export declare function createAlertState(): AlertState;
225
+ export type AlertThresholds = Pick<WatchOptions, "alertLatencyMs" | "alertBlockTimeSeconds">;
226
+ interface AlertSignal {
227
+ metric: "latency" | "block-time";
228
+ direction: "breach" | "clear";
229
+ value: number;
230
+ threshold: number;
231
+ }
232
+ /**
233
+ * Edge-triggered thresholds: one alert when a metric rises above its limit and
234
+ * one when it falls back under it, so a sustained breach does not repeat on
235
+ * every sample.
236
+ */
237
+ export declare function evaluateAlerts(metrics: WatchMetrics, thresholds: AlertThresholds, state: AlertState): {
238
+ state: AlertState;
239
+ alerts: AlertSignal[];
240
+ };
241
+ export interface WatchSummary {
242
+ samples: number;
243
+ errors: number;
244
+ firstBlock: bigint | null;
245
+ lastBlock: bigint | null;
246
+ advancedBy: bigint;
247
+ chainDrift: boolean;
248
+ stalls: number;
249
+ gasSurges: number;
250
+ alerts: number;
251
+ lastGasWei: bigint | null;
252
+ peakGasWei: bigint | null;
253
+ metrics: WatchMetrics;
254
+ /** Whole-run totals, independent of the rolling window. */
255
+ session: SessionMetrics;
256
+ durationMs: number;
257
+ aborted: boolean;
258
+ portfolio: PortfolioSummary | null;
259
+ }
260
+ export interface PortfolioSummary {
261
+ samples: number;
262
+ native: {
263
+ symbol: string;
264
+ decimals: number;
265
+ first: bigint;
266
+ last: bigint;
267
+ delta: bigint;
268
+ } | null;
269
+ tokens: Array<{
270
+ address: Address;
271
+ symbol: string;
272
+ label: string | null;
273
+ decimals: number | null;
274
+ first: bigint | null;
275
+ last: bigint | null;
276
+ delta: bigint | null;
277
+ }>;
278
+ }
279
+ export interface WatchDeps {
280
+ now?: () => number;
281
+ sleep?: (ms: number) => Promise<void>;
282
+ /** Injected portfolio reader; defaults to readBalances with an in-memory cache. */
283
+ readPortfolio?: () => Promise<BalancesReport>;
284
+ /** Injected price reader; defaults to DefiLlama with a 60 s cache. */
285
+ readPrices?: (tokens: Address[]) => Promise<PriceBook>;
286
+ /** Receives each portfolio Multicall3 chunk as it settles. */
287
+ onChunkProgress?: (progress: ChunkProgress) => void;
288
+ }
289
+ export interface BalanceChange {
290
+ delta: bigint;
291
+ /** Percent of the previous balance, rounded; null when it was zero. */
292
+ changePercent: number | null;
293
+ direction: "up" | "down";
294
+ }
295
+ /**
296
+ * Compare two readings of the same balance. Returns null unless the move is
297
+ * strictly larger than `thresholdPercent`. A balance that was zero has no
298
+ * percentage baseline, so any move away from zero alerts.
299
+ */
300
+ export declare function describeBalanceChange(previous: bigint, balance: bigint, thresholdPercent: number): BalanceChange | null;
301
+ export declare function watchChain(client: PublicClient, config: ChainConfig, options: WatchOptions, onEvent: (event: WatchEvent) => unknown, signal?: AbortSignal, deps?: WatchDeps): Promise<WatchSummary>;
302
+ export declare function formatWatchEvent(event: WatchEvent, config: ChainConfig): string;
303
+ export declare function formatWatchSummary(summary: WatchSummary): string;
304
+ export declare function toWatchEventJson(event: WatchEvent): Record<string, unknown>;
305
+ export declare function toWatchSummaryJson(summary: WatchSummary): Record<string, unknown>;
306
+ export {};