lemon-model 1.2.2 → 1.2.4
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/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logtrace/index.js +11 -0
- package/dist/esm/logtrace/index.js.map +1 -0
- package/dist/esm/logtrace/logtrace.js +251 -0
- package/dist/esm/logtrace/logtrace.js.map +1 -0
- package/dist/esm/logtrace/testing.js +77 -0
- package/dist/esm/logtrace/testing.js.map +1 -0
- package/dist/esm/progress/index.js +9 -0
- package/dist/esm/progress/index.js.map +1 -0
- package/dist/esm/progress/progress.js +256 -0
- package/dist/esm/progress/progress.js.map +1 -0
- package/dist/esm/progress/testing.js +98 -0
- package/dist/esm/progress/testing.js.map +1 -0
- package/dist/esm/socket/decorators.js +266 -0
- package/dist/esm/socket/decorators.js.map +1 -0
- package/dist/esm/socket/index.js +2 -0
- package/dist/esm/socket/index.js.map +1 -1
- package/dist/esm/socket/multi.js +94 -0
- package/dist/esm/socket/multi.js.map +1 -0
- package/dist/esm/socket/socket.js +82 -22
- package/dist/esm/socket/socket.js.map +1 -1
- package/dist/esm/socket/transport.js +385 -3
- package/dist/esm/socket/transport.js.map +1 -1
- package/dist/esm/socket/websocket.js +18 -4
- package/dist/esm/socket/websocket.js.map +1 -1
- package/dist/esm/sync/client.js +166 -0
- package/dist/esm/sync/client.js.map +1 -0
- package/dist/esm/sync/index.js +14 -0
- package/dist/esm/sync/index.js.map +1 -0
- package/dist/esm/sync/machine.js +181 -0
- package/dist/esm/sync/machine.js.map +1 -0
- package/dist/esm/sync/network.js +273 -0
- package/dist/esm/sync/network.js.map +1 -0
- package/dist/esm/sync/testing.js +44 -0
- package/dist/esm/sync/testing.js.map +1 -0
- package/dist/esm/sync/ticker.js +53 -0
- package/dist/esm/sync/ticker.js.map +1 -0
- package/dist/esm/sync/types.js +2 -0
- package/dist/{proxy → esm/sync}/types.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/logtrace/index.d.ts +7 -0
- package/dist/logtrace/index.js +27 -0
- package/dist/logtrace/index.js.map +1 -0
- package/dist/logtrace/logtrace.d.ts +99 -0
- package/dist/logtrace/logtrace.js +256 -0
- package/dist/logtrace/logtrace.js.map +1 -0
- package/dist/logtrace/testing.d.ts +40 -0
- package/dist/logtrace/testing.js +81 -0
- package/dist/logtrace/testing.js.map +1 -0
- package/dist/progress/index.d.ts +8 -0
- package/dist/{proxy → progress}/index.js +5 -9
- package/dist/progress/index.js.map +1 -0
- package/dist/progress/progress.d.ts +112 -0
- package/dist/progress/progress.js +263 -0
- package/dist/progress/progress.js.map +1 -0
- package/dist/progress/testing.d.ts +33 -0
- package/dist/progress/testing.js +102 -0
- package/dist/progress/testing.js.map +1 -0
- package/dist/socket/client/index.d.ts +9 -0
- package/dist/socket/client/index.js +26 -0
- package/dist/socket/client/index.js.map +1 -0
- package/dist/socket/client/keep-alive-controller.d.ts +35 -0
- package/dist/socket/client/keep-alive-controller.js +101 -0
- package/dist/socket/client/keep-alive-controller.js.map +1 -0
- package/dist/socket/client/message-router.d.ts +15 -0
- package/dist/socket/client/message-router.js +52 -0
- package/dist/socket/client/message-router.js.map +1 -0
- package/dist/socket/client/pending-request-store.d.ts +24 -0
- package/dist/socket/client/pending-request-store.js +78 -0
- package/dist/socket/client/pending-request-store.js.map +1 -0
- package/dist/socket/client/reconnect-controller.d.ts +56 -0
- package/dist/socket/client/reconnect-controller.js +177 -0
- package/dist/socket/client/reconnect-controller.js.map +1 -0
- package/dist/socket/client/rotation-controller.d.ts +32 -0
- package/dist/socket/client/rotation-controller.js +76 -0
- package/dist/socket/client/rotation-controller.js.map +1 -0
- package/dist/socket/client/shared-timer-scheduler.d.ts +17 -0
- package/dist/socket/client/shared-timer-scheduler.js +77 -0
- package/dist/socket/client/shared-timer-scheduler.js.map +1 -0
- package/dist/socket/client/socket-client.d.ts +2 -0
- package/dist/socket/client/socket-client.js +219 -0
- package/dist/socket/client/socket-client.js.map +1 -0
- package/dist/socket/client/types.d.ts +101 -0
- package/dist/socket/client/types.js +3 -0
- package/dist/socket/client/types.js.map +1 -0
- package/dist/socket/client/websocket-client-transport.d.ts +23 -0
- package/dist/socket/client/websocket-client-transport.js +152 -0
- package/dist/socket/client/websocket-client-transport.js.map +1 -0
- package/dist/socket/decorators.d.ts +38 -0
- package/dist/socket/decorators.js +271 -0
- package/dist/socket/decorators.js.map +1 -0
- package/dist/socket/index.d.ts +2 -0
- package/dist/socket/index.js +2 -0
- package/dist/socket/index.js.map +1 -1
- package/dist/socket/multi.d.ts +33 -0
- package/dist/socket/multi.js +98 -0
- package/dist/socket/multi.js.map +1 -0
- package/dist/socket/socket.d.ts +22 -4
- package/dist/socket/socket.js +82 -22
- package/dist/socket/socket.js.map +1 -1
- package/dist/socket/transport.d.ts +124 -6
- package/dist/socket/transport.js +389 -4
- package/dist/socket/transport.js.map +1 -1
- package/dist/socket/websocket.d.ts +14 -0
- package/dist/socket/websocket.js +19 -5
- package/dist/socket/websocket.js.map +1 -1
- package/dist/sync/client.d.ts +16 -0
- package/dist/sync/client.js +171 -0
- package/dist/sync/client.js.map +1 -0
- package/dist/sync/index.d.ts +10 -0
- package/dist/sync/index.js +30 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/machine.d.ts +3 -0
- package/dist/sync/machine.js +185 -0
- package/dist/sync/machine.js.map +1 -0
- package/dist/sync/network.d.ts +38 -0
- package/dist/sync/network.js +278 -0
- package/dist/sync/network.js.map +1 -0
- package/dist/sync/testing.d.ts +38 -0
- package/dist/sync/testing.js +48 -0
- package/dist/sync/testing.js.map +1 -0
- package/dist/sync/ticker.d.ts +21 -0
- package/dist/sync/ticker.js +57 -0
- package/dist/sync/ticker.js.map +1 -0
- package/dist/sync/types.d.ts +115 -0
- package/dist/sync/types.js +3 -0
- package/dist/sync/types.js.map +1 -0
- package/package.json +13 -1
- package/dist/proxy/index.d.ts +0 -12
- package/dist/proxy/index.js.map +0 -1
- package/dist/proxy/proxy.d.ts +0 -75
- package/dist/proxy/proxy.js +0 -198
- package/dist/proxy/proxy.js.map +0 -1
- package/dist/proxy/transport.d.ts +0 -123
- package/dist/proxy/transport.js +0 -401
- package/dist/proxy/transport.js.map +0 -1
- package/dist/proxy/types.d.ts +0 -89
- package/dist/proxy/types.js +0 -12
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sync/network.ts`
|
|
3
|
+
* - L1 network decorators: reconnect-on-death wrapper and raw wire translator.
|
|
4
|
+
* - additive to `src/socket`; free to compose with `createFilteredNetwork` (translated -> filtered -> L3).
|
|
5
|
+
*
|
|
6
|
+
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import { WEBSOCKET_NETWORK_SCOPE, } from '../socket/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* default watchdog cadence for readyState-based death detection.
|
|
11
|
+
* needed because an in-memory `Network.close()` notifies no one (see `socket/socket.ts`); only a
|
|
12
|
+
* real `OwnedWebSocketNetwork`/`BrowserWebSocketNetwork` close notifies via `onError` (see below),
|
|
13
|
+
* so the watchdog is a fallback and can stay slow — 1s keeps idle browser cost negligible.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_WATCHDOG_MS = 1000;
|
|
16
|
+
/** create the L1 reconnect decorator: swaps the internal network on death, keeping instance identity for L3 */
|
|
17
|
+
export const createReconnectingNetwork = (factory, options) => new ReconnectingNetwork(factory, options);
|
|
18
|
+
/** `NetworkSupportable` decorator that transparently swaps its internal network on death */
|
|
19
|
+
class ReconnectingNetwork {
|
|
20
|
+
constructor(factory, options) {
|
|
21
|
+
var _a, _b, _c, _d;
|
|
22
|
+
this.factory = factory;
|
|
23
|
+
this._generation = 0;
|
|
24
|
+
/** connected: 정상 감시 | connecting: 후보 open 대기 | backoff: 재시도 대기 | closed: 영구 종료 */
|
|
25
|
+
this.phase = 'connected';
|
|
26
|
+
this.retryCount = 0;
|
|
27
|
+
this.lastMessageAt = Date.now();
|
|
28
|
+
this.messageHandlers = new Set();
|
|
29
|
+
this.errorHandlers = new Set();
|
|
30
|
+
this.reconnectHandlers = new Set();
|
|
31
|
+
this.baseMs = (_a = options === null || options === void 0 ? void 0 : options.baseMs) !== null && _a !== void 0 ? _a : 1000;
|
|
32
|
+
this.factor = (_b = options === null || options === void 0 ? void 0 : options.factor) !== null && _b !== void 0 ? _b : 2;
|
|
33
|
+
this.maxMs = (_c = options === null || options === void 0 ? void 0 : options.maxMs) !== null && _c !== void 0 ? _c : 30000;
|
|
34
|
+
this.maxRetries = options === null || options === void 0 ? void 0 : options.maxRetries;
|
|
35
|
+
this.idleTimeoutMs = options === null || options === void 0 ? void 0 : options.idleTimeoutMs;
|
|
36
|
+
this.delayMs = this.baseMs;
|
|
37
|
+
this.current = factory();
|
|
38
|
+
this.attach(this.current);
|
|
39
|
+
this.watchdogTimer = setInterval(() => this.watch(), (_d = options === null || options === void 0 ? void 0 : options.watchdogMs) !== null && _d !== void 0 ? _d : DEFAULT_WATCHDOG_MS);
|
|
40
|
+
}
|
|
41
|
+
/** internal network generation (0 initially, +1 per reconnect) */
|
|
42
|
+
get generation() {
|
|
43
|
+
return this._generation;
|
|
44
|
+
}
|
|
45
|
+
get readyState() {
|
|
46
|
+
return this.phase === 'closed' ? 'closed' : this.current.readyState;
|
|
47
|
+
}
|
|
48
|
+
ready() {
|
|
49
|
+
var _a, _b, _c;
|
|
50
|
+
return (_c = (_b = (_a = this.current).ready) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : Promise.resolve();
|
|
51
|
+
}
|
|
52
|
+
onOpen(handler) {
|
|
53
|
+
var _a, _b, _c;
|
|
54
|
+
return (_c = (_b = (_a = this.current).onOpen) === null || _b === void 0 ? void 0 : _b.call(_a, handler)) !== null && _c !== void 0 ? _c : (() => undefined);
|
|
55
|
+
}
|
|
56
|
+
/** while disconnected (mid-reconnect or permanently closed) this throws synchronously; no send queuing */
|
|
57
|
+
send(data) {
|
|
58
|
+
if (this.phase === 'closed')
|
|
59
|
+
throw new Error(`@network is closed - reconnectingNetwork.send`);
|
|
60
|
+
if (this.current.readyState !== 'open') {
|
|
61
|
+
throw new Error(`@network is not connected - reconnectingNetwork.send`);
|
|
62
|
+
}
|
|
63
|
+
this.current.send(data);
|
|
64
|
+
}
|
|
65
|
+
onMessage(handler) {
|
|
66
|
+
this.messageHandlers.add(handler);
|
|
67
|
+
return () => this.messageHandlers.delete(handler);
|
|
68
|
+
}
|
|
69
|
+
onError(handler) {
|
|
70
|
+
this.errorHandlers.add(handler);
|
|
71
|
+
return () => this.errorHandlers.delete(handler);
|
|
72
|
+
}
|
|
73
|
+
onReconnect(handler) {
|
|
74
|
+
this.reconnectHandlers.add(handler);
|
|
75
|
+
return () => this.reconnectHandlers.delete(handler);
|
|
76
|
+
}
|
|
77
|
+
/** options are remembered and re-applied to every reconnected generation */
|
|
78
|
+
configure(options) {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
this.configured = Object.assign(Object.assign({}, this.configured), options);
|
|
81
|
+
(_b = (_a = this.current).configure) === null || _b === void 0 ? void 0 : _b.call(_a, this.configured);
|
|
82
|
+
}
|
|
83
|
+
/** stop reconnecting and close the internal network for good */
|
|
84
|
+
close(code, reason) {
|
|
85
|
+
if (this.phase === 'closed')
|
|
86
|
+
return;
|
|
87
|
+
this.phase = 'closed';
|
|
88
|
+
clearInterval(this.watchdogTimer);
|
|
89
|
+
if (this.reconnectTimer)
|
|
90
|
+
clearTimeout(this.reconnectTimer);
|
|
91
|
+
this.detach();
|
|
92
|
+
this.current.close(code, reason);
|
|
93
|
+
this.messageHandlers.clear();
|
|
94
|
+
this.errorHandlers.clear();
|
|
95
|
+
this.reconnectHandlers.clear();
|
|
96
|
+
}
|
|
97
|
+
attach(network) {
|
|
98
|
+
this.unsubscribeMessage = network.onMessage(raw => {
|
|
99
|
+
this.lastMessageAt = Date.now();
|
|
100
|
+
for (const handler of [...this.messageHandlers])
|
|
101
|
+
handler(raw);
|
|
102
|
+
});
|
|
103
|
+
this.unsubscribeError = network.onError((error, context) => {
|
|
104
|
+
for (const handler of [...this.errorHandlers])
|
|
105
|
+
handler(error, Object.assign(Object.assign({}, context), { network: this }));
|
|
106
|
+
//! `OwnedWebSocketNetwork`/`BrowserWebSocketNetwork` notify a close via onError with this scope
|
|
107
|
+
//! (see `WEBSOCKET_NETWORK_SCOPE` in `socket/websocket.ts`). other onError calls (e.g. delivery
|
|
108
|
+
//! errors) are forwarded above but do not by themselves mean the network died.
|
|
109
|
+
if (context.scope === WEBSOCKET_NETWORK_SCOPE.ownedClose ||
|
|
110
|
+
context.scope === WEBSOCKET_NETWORK_SCOPE.browserClose) {
|
|
111
|
+
this.onInnerDeath();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
detach() {
|
|
116
|
+
var _a, _b, _c;
|
|
117
|
+
(_a = this.unsubscribeMessage) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
118
|
+
(_b = this.unsubscribeError) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
119
|
+
(_c = this.unsubscribeCandidateOpen) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
120
|
+
}
|
|
121
|
+
onInnerDeath() {
|
|
122
|
+
if (this.phase === 'connected')
|
|
123
|
+
this.beginBackoff();
|
|
124
|
+
else if (this.phase === 'connecting')
|
|
125
|
+
this.failAttempt(new Error(`@candidate network died before open - reconnectingNetwork`), 'reconnectingNetwork.connect');
|
|
126
|
+
}
|
|
127
|
+
/** watchdog fallback for networks that close without notifying (e.g. in-memory `Network.close()`) */
|
|
128
|
+
watch() {
|
|
129
|
+
const state = this.current.readyState;
|
|
130
|
+
if (this.phase === 'connected') {
|
|
131
|
+
if (state === 'closing' || state === 'closed')
|
|
132
|
+
return this.beginBackoff();
|
|
133
|
+
if (this.idleTimeoutMs && Date.now() - this.lastMessageAt > this.idleTimeoutMs)
|
|
134
|
+
this.beginBackoff();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (this.phase === 'connecting') {
|
|
138
|
+
if (state === 'open')
|
|
139
|
+
return this.settleReconnected(); // onOpen 없는 network용 fallback
|
|
140
|
+
if (state === 'closing' || state === 'closed')
|
|
141
|
+
this.onInnerDeath();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
beginBackoff() {
|
|
145
|
+
this.detach();
|
|
146
|
+
this.phase = 'backoff';
|
|
147
|
+
this.reconnectTimer = setTimeout(() => this.attemptReconnect(), this.delayMs);
|
|
148
|
+
}
|
|
149
|
+
attemptReconnect() {
|
|
150
|
+
var _a, _b;
|
|
151
|
+
if (this.phase === 'closed')
|
|
152
|
+
return;
|
|
153
|
+
if (this.maxRetries != null && this.retryCount >= this.maxRetries) {
|
|
154
|
+
this.phase = 'closed';
|
|
155
|
+
clearInterval(this.watchdogTimer);
|
|
156
|
+
const error = new Error(`@network exceeded maxRetries[${this.maxRetries}] - reconnectingNetwork`);
|
|
157
|
+
for (const handler of [...this.errorHandlers])
|
|
158
|
+
handler(error, { scope: 'reconnectingNetwork.maxRetries', network: this });
|
|
159
|
+
this.messageHandlers.clear();
|
|
160
|
+
this.errorHandlers.clear();
|
|
161
|
+
this.reconnectHandlers.clear();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
let next;
|
|
165
|
+
try {
|
|
166
|
+
next = this.factory();
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
this.failAttempt(e, 'reconnectingNetwork.factory');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.current = next;
|
|
173
|
+
this.attach(next);
|
|
174
|
+
if (this.configured)
|
|
175
|
+
(_a = next.configure) === null || _a === void 0 ? void 0 : _a.call(next, this.configured);
|
|
176
|
+
this.phase = 'connecting';
|
|
177
|
+
//! success is declared only once the candidate actually OPENS. a factory return alone is not a
|
|
178
|
+
//! connection (a real WebSocket constructs fine while the server is down), so resetting backoff
|
|
179
|
+
//! here would degrade to a constant-rate reconnect storm with an onReconnect/tick per attempt.
|
|
180
|
+
const state = next.readyState;
|
|
181
|
+
if (state === 'open')
|
|
182
|
+
return this.settleReconnected();
|
|
183
|
+
if (state === 'closing' || state === 'closed')
|
|
184
|
+
return this.onInnerDeath();
|
|
185
|
+
this.unsubscribeCandidateOpen = (_b = next.onOpen) === null || _b === void 0 ? void 0 : _b.call(next, () => {
|
|
186
|
+
if (this.phase === 'connecting' && this.current === next)
|
|
187
|
+
this.settleReconnected();
|
|
188
|
+
});
|
|
189
|
+
//! a candidate stuck in 'connecting' is bounded by the inner network's own connect timeout
|
|
190
|
+
//! (e.g. `OwnedWebSocketNetwork.connectTimeoutMs`), which actual-closes and lands in onInnerDeath.
|
|
191
|
+
}
|
|
192
|
+
/** a reconnect attempt failed (factory throw, or candidate died before open): keep growing the backoff */
|
|
193
|
+
failAttempt(error, scope) {
|
|
194
|
+
this.detach();
|
|
195
|
+
this.retryCount++;
|
|
196
|
+
this.delayMs = Math.min(this.delayMs * this.factor, this.maxMs);
|
|
197
|
+
for (const handler of [...this.errorHandlers])
|
|
198
|
+
handler(error, { scope, network: this });
|
|
199
|
+
this.phase = 'backoff';
|
|
200
|
+
this.reconnectTimer = setTimeout(() => this.attemptReconnect(), this.delayMs);
|
|
201
|
+
}
|
|
202
|
+
/** the candidate opened: only now reset the backoff/retry budget and notify onReconnect */
|
|
203
|
+
settleReconnected() {
|
|
204
|
+
var _a;
|
|
205
|
+
(_a = this.unsubscribeCandidateOpen) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
206
|
+
this.unsubscribeCandidateOpen = undefined;
|
|
207
|
+
this.phase = 'connected';
|
|
208
|
+
this._generation++;
|
|
209
|
+
this.retryCount = 0;
|
|
210
|
+
this.delayMs = this.baseMs;
|
|
211
|
+
this.lastMessageAt = Date.now();
|
|
212
|
+
for (const handler of [...this.reconnectHandlers])
|
|
213
|
+
handler();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/** create the L1 wire translator decorator over a raw string, same slot as `createFilteredNetwork` */
|
|
217
|
+
export const createTranslatedNetwork = (source, translator) => new TranslatedNetwork(source, translator);
|
|
218
|
+
/** `NetworkSupportable` decorator that translates raw strings at the wire boundary */
|
|
219
|
+
class TranslatedNetwork {
|
|
220
|
+
constructor(source, translator) {
|
|
221
|
+
this.source = source;
|
|
222
|
+
this.translator = translator;
|
|
223
|
+
this.errorHandlers = new Set();
|
|
224
|
+
this.unsubscribeSourceError = source.onError((error, context) => this.emitError(error, context));
|
|
225
|
+
}
|
|
226
|
+
get readyState() {
|
|
227
|
+
return this.source.readyState;
|
|
228
|
+
}
|
|
229
|
+
ready() {
|
|
230
|
+
var _a, _b, _c;
|
|
231
|
+
return (_c = (_b = (_a = this.source).ready) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : Promise.resolve();
|
|
232
|
+
}
|
|
233
|
+
onOpen(handler) {
|
|
234
|
+
var _a, _b, _c;
|
|
235
|
+
return (_c = (_b = (_a = this.source).onOpen) === null || _b === void 0 ? void 0 : _b.call(_a, handler)) !== null && _c !== void 0 ? _c : (() => undefined);
|
|
236
|
+
}
|
|
237
|
+
send(data) {
|
|
238
|
+
this.source.send(this.translator.outbound ? this.translator.outbound(data) : data);
|
|
239
|
+
}
|
|
240
|
+
onMessage(handler) {
|
|
241
|
+
return this.source.onMessage(raw => {
|
|
242
|
+
let translated;
|
|
243
|
+
try {
|
|
244
|
+
translated = this.translator.inbound ? this.translator.inbound(raw) : raw;
|
|
245
|
+
}
|
|
246
|
+
catch (e) {
|
|
247
|
+
this.emitError(e, { scope: 'translatedNetwork.inbound' });
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (translated === undefined)
|
|
251
|
+
return; // dropped by translator
|
|
252
|
+
handler(translated);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
configure(options) {
|
|
256
|
+
var _a, _b;
|
|
257
|
+
(_b = (_a = this.source).configure) === null || _b === void 0 ? void 0 : _b.call(_a, options);
|
|
258
|
+
}
|
|
259
|
+
onError(handler) {
|
|
260
|
+
this.errorHandlers.add(handler);
|
|
261
|
+
return () => this.errorHandlers.delete(handler);
|
|
262
|
+
}
|
|
263
|
+
close(code, reason) {
|
|
264
|
+
this.unsubscribeSourceError();
|
|
265
|
+
this.errorHandlers.clear();
|
|
266
|
+
this.source.close(code, reason);
|
|
267
|
+
}
|
|
268
|
+
emitError(error, context) {
|
|
269
|
+
for (const handler of [...this.errorHandlers])
|
|
270
|
+
handler(error, Object.assign(Object.assign({}, context), { network: this }));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../../src/sync/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sync/testing.ts`
|
|
3
|
+
* - bridges the in-memory `Peer` simulator into a single `NetworkSupportable` for L3/L4 specs.
|
|
4
|
+
* - test/dev only; kept OUT of `sync/index.ts` so production bundles never pull in the simulator runtime.
|
|
5
|
+
*
|
|
6
|
+
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
//! simulator runtime lives in the isolated `../socket/testing` module (kept out of the root barrel).
|
|
9
|
+
import { createNetwork, createPeer } from '../socket/testing.js';
|
|
10
|
+
/**
|
|
11
|
+
* create a connected client/server `Peer` pair and expose the client side as one `NetworkSupportable`.
|
|
12
|
+
*
|
|
13
|
+
* `Peer.dispatch` settles an envelope against its own pending map, and otherwise fans every remaining
|
|
14
|
+
* envelope out to `Peer.onMessage()` listeners whose return value becomes an automatic `result` reply
|
|
15
|
+
* (regardless of whether the listener actually returns anything). A client-side bridge built on
|
|
16
|
+
* `clientPeer.post()` + `clientPeer.onMessage()` therefore echoes every pull result and every server
|
|
17
|
+
* event straight back to the server as an empty `result`, and — since the server has no pending for
|
|
18
|
+
* that mid either — the server echoes it right back, forever. `send()` and `onMessage()` below instead
|
|
19
|
+
* talk to the raw uplink/downlink `Network` instances directly, bypassing `Peer` dispatch on the client
|
|
20
|
+
* side entirely, so no such reply is ever produced. The `server` `Peer` itself is untouched and keeps
|
|
21
|
+
* its normal `onMessage()`/`post()` contract for the simulated server band.
|
|
22
|
+
*/
|
|
23
|
+
export const createPeerBridge = (options) => {
|
|
24
|
+
let serverNetwork;
|
|
25
|
+
const server = createPeer(Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.server), { networkFactory: context => (serverNetwork = createNetwork(Object.assign({ id: context.id, fromPeerId: context.fromPeerId, toPeerId: context.toPeerId, logger: context.logger }, context.options))) }));
|
|
26
|
+
const client = createPeer(options === null || options === void 0 ? void 0 : options.client);
|
|
27
|
+
const clientId = client.connect(server);
|
|
28
|
+
const clientNetwork = client.network;
|
|
29
|
+
if (!clientNetwork || !serverNetwork) {
|
|
30
|
+
throw new Error(`@peer bridge network capture failed - sync.testing.createPeerBridge`);
|
|
31
|
+
}
|
|
32
|
+
const network = {
|
|
33
|
+
get readyState() {
|
|
34
|
+
return client.readyState;
|
|
35
|
+
},
|
|
36
|
+
ready: () => client.ready(),
|
|
37
|
+
send: (data) => clientNetwork.send(data),
|
|
38
|
+
onMessage: handler => serverNetwork.onMessage(handler),
|
|
39
|
+
onError: handler => client.onError(handler),
|
|
40
|
+
close: () => client.close(),
|
|
41
|
+
};
|
|
42
|
+
return { network, server, serverNetwork, clientId };
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../src/sync/testing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,qGAAqG;AACrG,OAAO,EAAE,aAAa,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAoB3E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA2B,EAAc,EAAE;IACxE,IAAI,aAA6C,CAAC;IAClD,MAAM,MAAM,GAAoB,UAAU,iCACnC,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAClB,cAAc,EAAE,OAAO,CAAC,EAAE,CACtB,CAAC,aAAa,GAAG,aAAa,iBAC1B,EAAE,EAAE,OAAO,CAAC,EAAE,EACd,UAAU,EAAE,OAAO,CAAC,UAAU,EAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,IACnB,OAAO,CAAC,OAAO,EACpB,CAAC,IACT,CAAC;IACH,MAAM,MAAM,GAAoB,UAAU,CAAC,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC;IACrC,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,EAAE;QAClC,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;KAC1F;IAED,MAAM,OAAO,GAAuB;QAChC,IAAI,UAAU;YACV,OAAO,MAAM,CAAC,UAAU,CAAC;QAC7B,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;QAC3B,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,aAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QACjD,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,aAAc,CAAC,SAAS,CAAC,OAAO,CAAC;QACvD,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;QAC3C,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;KAC9B,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AACxD,CAAC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** create a self-rescheduling ticker: no overlap, backoff on failure, restore on success */
|
|
2
|
+
export const createSyncTicker = (tick, options) => new SyncTicker(tick, options);
|
|
3
|
+
class SyncTicker {
|
|
4
|
+
constructor(tick, options) {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
this.tick = tick;
|
|
7
|
+
this.options = options;
|
|
8
|
+
this._running = false;
|
|
9
|
+
/** bumped on every start()/stop(): an in-flight tick from an old epoch must not reschedule a second chain */
|
|
10
|
+
this.epoch = 0;
|
|
11
|
+
this.factor = (_a = options.factor) !== null && _a !== void 0 ? _a : 2;
|
|
12
|
+
this.maxMs = (_b = options.maxMs) !== null && _b !== void 0 ? _b : 60000;
|
|
13
|
+
this.delayMs = options.intervalMs;
|
|
14
|
+
}
|
|
15
|
+
get running() {
|
|
16
|
+
return this._running;
|
|
17
|
+
}
|
|
18
|
+
start() {
|
|
19
|
+
if (this._running)
|
|
20
|
+
return; // re-entrant start() is a no-op
|
|
21
|
+
this._running = true;
|
|
22
|
+
this.epoch++;
|
|
23
|
+
this.delayMs = this.options.intervalMs;
|
|
24
|
+
this.schedule(this.epoch);
|
|
25
|
+
}
|
|
26
|
+
stop() {
|
|
27
|
+
this._running = false;
|
|
28
|
+
this.epoch++;
|
|
29
|
+
if (this.timer)
|
|
30
|
+
clearTimeout(this.timer);
|
|
31
|
+
this.timer = undefined;
|
|
32
|
+
}
|
|
33
|
+
schedule(epoch) {
|
|
34
|
+
if (!this._running || epoch !== this.epoch)
|
|
35
|
+
return;
|
|
36
|
+
this.timer = setTimeout(() => this.run(epoch), this.delayMs);
|
|
37
|
+
}
|
|
38
|
+
/** the next tick is scheduled only after this one settles (setTimeout chain) - no overlap */
|
|
39
|
+
run(epoch) {
|
|
40
|
+
this.tick().then(() => {
|
|
41
|
+
if (epoch !== this.epoch)
|
|
42
|
+
return; // stale chain (stopped/restarted while in flight)
|
|
43
|
+
this.delayMs = this.options.intervalMs;
|
|
44
|
+
this.schedule(epoch);
|
|
45
|
+
}, () => {
|
|
46
|
+
if (epoch !== this.epoch)
|
|
47
|
+
return; // stale chain (stopped/restarted while in flight)
|
|
48
|
+
this.delayMs = Math.min(this.delayMs * this.factor, this.maxMs);
|
|
49
|
+
this.schedule(epoch);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=ticker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticker.js","sourceRoot":"","sources":["../../../src/sync/ticker.ts"],"names":[],"mappings":"AAqBA,4FAA4F;AAC5F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAA4B,EAAE,OAA0B,EAAyB,EAAE,CAChH,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAElC,MAAM,UAAU;IASZ,YAAoC,IAA4B,EAAmB,OAA0B;;QAAzE,SAAI,GAAJ,IAAI,CAAwB;QAAmB,YAAO,GAAP,OAAO,CAAmB;QAJrG,aAAQ,GAAG,KAAK,CAAC;QACzB,6GAA6G;QACrG,UAAK,GAAG,CAAC,CAAC;QAGd,IAAI,CAAC,MAAM,GAAG,MAAA,OAAO,CAAC,MAAM,mCAAI,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,MAAA,OAAO,CAAC,KAAK,mCAAI,KAAM,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IACtC,CAAC;IAED,IAAW,OAAO;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAEM,KAAK;QACR,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,gCAAgC;QAC3D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAEM,IAAI;QACP,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,IAAI,CAAC,KAAK;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IAC3B,CAAC;IAEO,QAAQ,CAAC,KAAa;QAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO;QACnD,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC;IAED,6FAA6F;IACrF,GAAG,CAAC,KAAa;QACrB,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CACZ,GAAG,EAAE;YACD,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;gBAAE,OAAO,CAAC,kDAAkD;YACpF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;YACvC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC,EACD,GAAG,EAAE;YACD,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;gBAAE,OAAO,CAAC,kDAAkD;YACpF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAChE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC,CACJ,CAAC;IACN,CAAC;CACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/sync/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -29,4 +29,7 @@ __exportStar(require("./cores"), exports);
|
|
|
29
29
|
__exportStar(require("./socket"), exports);
|
|
30
30
|
__exportStar(require("./genai"), exports);
|
|
31
31
|
__exportStar(require("./buffer"), exports);
|
|
32
|
+
__exportStar(require("./sync"), exports);
|
|
33
|
+
__exportStar(require("./progress"), exports);
|
|
34
|
+
__exportStar(require("./logtrace"), exports);
|
|
32
35
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,0CAAwB;AACxB,0CAAwB;AACxB,2CAAyB;AACzB,0CAAwB;AACxB,2CAAyB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,0CAAwB;AACxB,0CAAwB;AACxB,2CAAyB;AACzB,0CAAwB;AACxB,2CAAyB;AACzB,yCAAuB;AACvB,6CAA2B;AAC3B,6CAA2B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* `logtrace/index.ts`
|
|
19
|
+
* - one-way realtime log stream (reporter/consumer) over a shared socket.
|
|
20
|
+
*
|
|
21
|
+
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
22
|
+
*/
|
|
23
|
+
__exportStar(require("./logtrace"), exports);
|
|
24
|
+
//! NOTE: the verification loop harness (`./testing`) is intentionally NOT re-exported here.
|
|
25
|
+
//! It pulls in the in-memory socket simulator — import it via the isolated
|
|
26
|
+
//! `lemon-model/logtrace/testing` entry so production bundles stay clean.
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logtrace/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;GAKG;AACH,6CAA2B;AAE3B,4FAA4F;AAC5F,2EAA2E;AAC3E,0EAA0E"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `logtrace/logtrace.ts`
|
|
3
|
+
* - one-way (server -> client) realtime log stream over one shared WebSocket.
|
|
4
|
+
* - contracts + reporter(batching) + consumer(ring buffer) live in one file since
|
|
5
|
+
* both ends share the wire envelope/batch codec (see SPEC.md).
|
|
6
|
+
*
|
|
7
|
+
* @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
|
|
8
|
+
*/
|
|
9
|
+
import { NetworkSupportable, SocketMessage, SocketUnsubscribe } from '../socket/types';
|
|
10
|
+
/** log severity - same 4 levels as SocketLogLevel */
|
|
11
|
+
export declare type LogTraceLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
12
|
+
/** single log entry - the minimal unit crossing the wire */
|
|
13
|
+
export interface LogTraceEntry {
|
|
14
|
+
/** log severity */
|
|
15
|
+
level: LogTraceLevel;
|
|
16
|
+
/** epoch timestamp in milliseconds */
|
|
17
|
+
ts: number;
|
|
18
|
+
/** human-readable message */
|
|
19
|
+
message: string;
|
|
20
|
+
/** structured extra data (optional) */
|
|
21
|
+
json?: Record<string, any>;
|
|
22
|
+
/** monotonic sequence within a source - ordering/loss observation. issued only past the reporter minLevel gate */
|
|
23
|
+
seq: number;
|
|
24
|
+
/** sender identity - carried on the batch over the wire; filled by the consumer when storing */
|
|
25
|
+
source?: string;
|
|
26
|
+
/** true when json was dropped or message was cut by the size budget */
|
|
27
|
+
truncated?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** batch payload carried in SocketMessage.data */
|
|
30
|
+
export interface LogTraceBatch {
|
|
31
|
+
/** batch entries (reporter emit order) */
|
|
32
|
+
entries: LogTraceEntry[];
|
|
33
|
+
/** sender identity - unique per reporter (required). consumer dedup/loss key */
|
|
34
|
+
source: string;
|
|
35
|
+
}
|
|
36
|
+
/** server-side send path injection (Ports & Adapters). a rejected Promise is wired into onError */
|
|
37
|
+
export declare type LogTraceSink = (message: SocketMessage<LogTraceBatch>) => void | Promise<void>;
|
|
38
|
+
export interface LogTraceReporterOptions {
|
|
39
|
+
/** envelope type (default 'log:trace') */
|
|
40
|
+
type?: string;
|
|
41
|
+
/** sender identity - carried as the batch source. auto random id when omitted (invocation id recommended) */
|
|
42
|
+
source?: string;
|
|
43
|
+
/** levels below this are not sent at all (default 'debug' = everything) */
|
|
44
|
+
minLevel?: LogTraceLevel;
|
|
45
|
+
/** flush when this many entries are buffered (default 20) */
|
|
46
|
+
flushCount?: number;
|
|
47
|
+
/** flush this long after the first buffered entry. 0 disables the timer (default 250) */
|
|
48
|
+
flushIntervalMs?: number;
|
|
49
|
+
/** serialized batch byte budget. split-flush right before exceeding (default 3/4 of maxPacketBytes) */
|
|
50
|
+
maxBatchBytes?: number;
|
|
51
|
+
/** envelope size cap (default 64kb). a single oversized entry drops json + marks truncated */
|
|
52
|
+
maxPacketBytes?: number;
|
|
53
|
+
/** observe send failures and truncations */
|
|
54
|
+
onError?: (error: any, entries: LogTraceEntry[]) => void;
|
|
55
|
+
}
|
|
56
|
+
export interface LogTraceReporterSupportable {
|
|
57
|
+
/** record one log entry. auto-flushes when a flush condition is reached */
|
|
58
|
+
log(level: LogTraceLevel, message: string, json?: Record<string, any>): void;
|
|
59
|
+
/** level shortcut */
|
|
60
|
+
debug(message: string, json?: Record<string, any>): void;
|
|
61
|
+
info(message: string, json?: Record<string, any>): void;
|
|
62
|
+
warn(message: string, json?: Record<string, any>): void;
|
|
63
|
+
error(message: string, json?: Record<string, any>): void;
|
|
64
|
+
/** send the buffered entries now */
|
|
65
|
+
flush(): void;
|
|
66
|
+
/** flush + release the timer. must be called before a lambda invocation ends. later log calls are ignored */
|
|
67
|
+
close(): void;
|
|
68
|
+
}
|
|
69
|
+
/** query condition for consumer.list() */
|
|
70
|
+
export interface LogTraceQuery {
|
|
71
|
+
/** only this level and above */
|
|
72
|
+
minLevel?: LogTraceLevel;
|
|
73
|
+
/** last n entries (default all) */
|
|
74
|
+
limit?: number;
|
|
75
|
+
}
|
|
76
|
+
export interface LogTraceConsumerOptions {
|
|
77
|
+
/** inbound envelope type prefix (default 'log:') */
|
|
78
|
+
typePrefix?: string;
|
|
79
|
+
/** received entries below this level are discarded (default 'debug' = everything) */
|
|
80
|
+
minLevel?: LogTraceLevel;
|
|
81
|
+
/** ring buffer retention cap (default 1000) */
|
|
82
|
+
maxEntries?: number;
|
|
83
|
+
}
|
|
84
|
+
export interface LogTraceConsumerSupportable {
|
|
85
|
+
/** subscribe to received entries - batches are unpacked and notified one entry at a time, in batch order */
|
|
86
|
+
onEntry(handler: (entry: LogTraceEntry) => void): SocketUnsubscribe;
|
|
87
|
+
/** list retained entries - returned in (ts, seq) ascending order */
|
|
88
|
+
list(query?: LogTraceQuery): LogTraceEntry[];
|
|
89
|
+
/** observed wire loss - sum of (max seq - received count) per source. exact regardless of arrival order */
|
|
90
|
+
readonly gapCount: number;
|
|
91
|
+
/** drop retained entries (subscriptions stay) */
|
|
92
|
+
clear(): void;
|
|
93
|
+
/** unsubscribe from the network. does NOT close the network (shared socket) */
|
|
94
|
+
close(): void;
|
|
95
|
+
}
|
|
96
|
+
/** create a batching log reporter over an injected send path */
|
|
97
|
+
export declare const createLogTraceReporter: (sink: LogTraceSink, options?: LogTraceReporterOptions) => LogTraceReporterSupportable;
|
|
98
|
+
/** create a log consumer over a shared raw string network */
|
|
99
|
+
export declare const createLogTraceConsumer: (network: NetworkSupportable, options?: LogTraceConsumerOptions) => LogTraceConsumerSupportable;
|