@moxt-ai/mobius 0.0.295 → 0.0.296
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/cli.js +72 -40
- package/dist/cli.js.map +3 -3
- package/dist/runtime/relay/session-event-publisher.d.ts +2 -2
- package/dist/runtime/relay/session-event-publisher.d.ts.map +1 -1
- package/dist/runtime/relay/session-event-publisher.js +79 -42
- package/dist/runtime/relay/session-event-publisher.js.map +1 -1
- package/dist/runtime.js +72 -40
- package/dist/runtime.js.map +3 -3
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { WebSocket } from "undici";
|
|
|
3
3
|
import type { SessionEventSink } from "../../session/api/session-api.ts";
|
|
4
4
|
import type { Timer } from "../../util/timer.ts";
|
|
5
5
|
export declare const SESSION_EVENT_BATCH_WINDOW_MILLISECONDS = 100;
|
|
6
|
-
/**
|
|
6
|
+
/** Keeps unsent output in bounded memory across reconnects. Sent events are never replayed. */
|
|
7
7
|
export declare class RuntimeSessionEventPublisher implements SessionEventSink {
|
|
8
8
|
#private;
|
|
9
9
|
constructor(timer: Timer);
|
|
@@ -16,7 +16,7 @@ export declare class RuntimeSessionEventPublisher implements SessionEventSink {
|
|
|
16
16
|
readonly publishInfo: (event: SessionInfoUpdatedEvent) => void;
|
|
17
17
|
readonly publishClosed: (event: SessionCloseNoticeEvent) => void;
|
|
18
18
|
readonly publish: (event: SessionLiveEvent) => void;
|
|
19
|
-
private readonly
|
|
19
|
+
private readonly cancelFlush;
|
|
20
20
|
private readonly flushEvents;
|
|
21
21
|
}
|
|
22
22
|
//# sourceMappingURL=session-event-publisher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-publisher.d.ts","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAiB,KAAK,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"session-event-publisher.d.ts","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAiB,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAShE,eAAO,MAAM,uCAAuC,MAAM,CAAC;AAY3D,+FAA+F;AAC/F,qBAAa,4BAA6B,YAAW,gBAAgB;;IAQjE,YAAY,KAAK,EAAE,KAAK,EAEvB;IAED,QAAQ,CAAC,OAAO,WAAY,SAAS,KAAG,IAAI,CAO1C;IAEF,QAAQ,CAAC,UAAU,WAAY,SAAS,KAAG,IAAI,CAK7C;IAEF,QAAQ,CAAC,KAAK,QAAO,IAAI,CAKvB;IAEF,QAAQ,CAAC,KAAK,QAAO,IAAI,CAIvB;IAEF,QAAQ,CAAC,uBAAuB,cAAe,MAAM,aAAa,MAAM,QAAQ,MAAM,WAAW,MAAM,KAAG,IAAI,CAE5G;IACF,QAAQ,CAAC,aAAa,UAAW,yBAAyB,KAAG,IAAI,CAAsB;IACvF,QAAQ,CAAC,WAAW,UAAW,uBAAuB,KAAG,IAAI,CAAsB;IACnF,QAAQ,CAAC,aAAa,UAAW,uBAAuB,KAAG,IAAI,CAAsB;IAoBrF,QAAQ,CAAC,OAAO,UAAW,gBAAgB,KAAG,IAAI,CAwDhD;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAG1B;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CA2B1B;CACL"}
|
|
@@ -1,39 +1,47 @@
|
|
|
1
1
|
import { encodeDaemonToServiceMessage, SESSION_EVENT_BATCH_MAX_SIZE, SESSION_EVENT_KIND, } from "@moxt-ai/mobius-sdk/protocol";
|
|
2
2
|
import { WebSocket } from "undici";
|
|
3
3
|
const MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
|
|
4
|
+
const MAX_PENDING_BYTES = 32 * 1024 * 1024;
|
|
4
5
|
const MAX_EVENT_BATCH_BYTES = 1024 * 1024;
|
|
5
6
|
const MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
6
7
|
// Browser-compatible WebSocket clients may initiate only 1000 or application close codes.
|
|
7
8
|
const LOCAL_BACKPRESSURE_CLOSE_CODE = 4009;
|
|
8
9
|
const EMPTY_ENVELOPE_BYTES = Buffer.byteLength(JSON.stringify({ events: [], kind: SESSION_EVENT_KIND }));
|
|
9
10
|
export const SESSION_EVENT_BATCH_WINDOW_MILLISECONDS = 100;
|
|
10
|
-
/**
|
|
11
|
+
/** Keeps unsent output in bounded memory across reconnects. Sent events are never replayed. */
|
|
11
12
|
export class RuntimeSessionEventPublisher {
|
|
12
|
-
#
|
|
13
|
-
#pendingBytes =
|
|
13
|
+
#pending = [];
|
|
14
|
+
#pendingBytes = 0;
|
|
15
|
+
#overflowReported = false;
|
|
14
16
|
#pendingTask = null;
|
|
15
|
-
#
|
|
17
|
+
#connection = { kind: "disconnected" };
|
|
16
18
|
#timer;
|
|
17
19
|
constructor(timer) {
|
|
18
20
|
this.#timer = timer;
|
|
19
21
|
}
|
|
20
22
|
connect = (socket) => {
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
+
if (this.#connection.kind === "closed") {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.#connection = { kind: "connected", socket };
|
|
27
|
+
// Hand off the unsent tail before a new command can publish newer events.
|
|
28
|
+
this.flushEvents(socket);
|
|
23
29
|
};
|
|
24
30
|
disconnect = (socket) => {
|
|
25
|
-
if (this.#socket === socket) {
|
|
26
|
-
this.#
|
|
27
|
-
this.
|
|
31
|
+
if (this.#connection.kind === "connected" && this.#connection.socket === socket) {
|
|
32
|
+
this.#connection = { kind: "disconnected" };
|
|
33
|
+
this.cancelFlush();
|
|
28
34
|
}
|
|
29
35
|
};
|
|
30
36
|
close = () => {
|
|
31
|
-
this.#
|
|
32
|
-
this.
|
|
37
|
+
this.#connection = { kind: "closed" };
|
|
38
|
+
this.cancelFlush();
|
|
39
|
+
this.#pending.length = 0;
|
|
40
|
+
this.#pendingBytes = 0;
|
|
33
41
|
};
|
|
34
42
|
flush = () => {
|
|
35
|
-
if (this.#
|
|
36
|
-
this.flushEvents(this.#socket);
|
|
43
|
+
if (this.#connection.kind === "connected") {
|
|
44
|
+
this.flushEvents(this.#connection.socket);
|
|
37
45
|
}
|
|
38
46
|
};
|
|
39
47
|
publishOperationFailure = (sessionId, requestId, code, message) => {
|
|
@@ -43,10 +51,11 @@ export class RuntimeSessionEventPublisher {
|
|
|
43
51
|
publishInfo = (event) => this.#send(event);
|
|
44
52
|
publishClosed = (event) => this.#send(event);
|
|
45
53
|
#send = (message) => {
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
54
|
+
const connection = this.#connection;
|
|
55
|
+
if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket.OPEN) {
|
|
48
56
|
return;
|
|
49
57
|
}
|
|
58
|
+
const socket = connection.socket;
|
|
50
59
|
const encoded = encodeDaemonToServiceMessage(message);
|
|
51
60
|
if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
|
|
52
61
|
socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
|
|
@@ -60,8 +69,7 @@ export class RuntimeSessionEventPublisher {
|
|
|
60
69
|
}
|
|
61
70
|
};
|
|
62
71
|
publish = (event) => {
|
|
63
|
-
|
|
64
|
-
if (socket === null || socket.readyState !== WebSocket.OPEN) {
|
|
72
|
+
if (this.#connection.kind === "closed") {
|
|
65
73
|
return;
|
|
66
74
|
}
|
|
67
75
|
const bytes = Buffer.byteLength(JSON.stringify(event), "utf8") + 1;
|
|
@@ -74,45 +82,74 @@ export class RuntimeSessionEventPublisher {
|
|
|
74
82
|
});
|
|
75
83
|
return;
|
|
76
84
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
let batch = this.#pending.at(-1);
|
|
86
|
+
const newBatch = batch === undefined ||
|
|
87
|
+
batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE ||
|
|
88
|
+
batch.bytes + bytes > MAX_EVENT_BATCH_BYTES;
|
|
89
|
+
const additionalBytes = bytes + (newBatch ? EMPTY_ENVELOPE_BYTES : 0);
|
|
90
|
+
if (this.#pendingBytes + additionalBytes > MAX_PENDING_BYTES) {
|
|
91
|
+
if (!this.#overflowReported) {
|
|
92
|
+
this.#overflowReported = true;
|
|
93
|
+
console.warn("Live Session output exceeded the pending buffer limit", {
|
|
94
|
+
code: "live_event_buffer_full",
|
|
95
|
+
sessionId: event.sessionId,
|
|
96
|
+
eventId: event.eventId,
|
|
97
|
+
maximumBytes: MAX_PENDING_BYTES,
|
|
98
|
+
});
|
|
81
99
|
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (batch === undefined || newBatch) {
|
|
103
|
+
batch = { events: [], bytes: EMPTY_ENVELOPE_BYTES };
|
|
104
|
+
this.#pending.push(batch);
|
|
82
105
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
batch.events.push(event);
|
|
107
|
+
batch.bytes += bytes;
|
|
108
|
+
this.#pendingBytes += additionalBytes;
|
|
109
|
+
const connection = this.#connection;
|
|
110
|
+
if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket.OPEN) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const socket = connection.socket;
|
|
114
|
+
if (this.#pending.length > 1 ||
|
|
115
|
+
batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE ||
|
|
116
|
+
batch.bytes >= MAX_EVENT_BATCH_BYTES) {
|
|
86
117
|
this.flushEvents(socket);
|
|
87
118
|
return;
|
|
88
119
|
}
|
|
89
120
|
this.#pendingTask ??= this.#timer.schedule(() => this.flushEvents(socket), SESSION_EVENT_BATCH_WINDOW_MILLISECONDS);
|
|
90
121
|
};
|
|
91
|
-
|
|
122
|
+
cancelFlush = () => {
|
|
92
123
|
this.#pendingTask?.cancel();
|
|
93
124
|
this.#pendingTask = null;
|
|
94
|
-
this.#pendingEvents = [];
|
|
95
|
-
this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
|
|
96
125
|
};
|
|
97
126
|
flushEvents = (socket) => {
|
|
98
|
-
this
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.#pendingEvents = [];
|
|
102
|
-
this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
|
|
103
|
-
if (events.length === 0 || this.#socket !== socket || socket.readyState !== WebSocket.OPEN) {
|
|
127
|
+
this.cancelFlush();
|
|
128
|
+
const connection = this.#connection;
|
|
129
|
+
if (connection.kind !== "connected" || connection.socket !== socket || socket.readyState !== WebSocket.OPEN) {
|
|
104
130
|
return;
|
|
105
131
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
132
|
+
let attempted = 0;
|
|
133
|
+
for (const batch of this.#pending) {
|
|
134
|
+
const encoded = encodeDaemonToServiceMessage({ events: batch.events, kind: SESSION_EVENT_KIND });
|
|
135
|
+
if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
|
|
136
|
+
socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
// Once handed to the socket, a batch cannot be safely resent without acknowledgements.
|
|
140
|
+
attempted += 1;
|
|
141
|
+
this.#pendingBytes -= batch.bytes;
|
|
142
|
+
try {
|
|
143
|
+
socket.send(encoded);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
console.warn("Live Session output could not be sent", { code: "live_event_send_failed" });
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
113
149
|
}
|
|
114
|
-
|
|
115
|
-
|
|
150
|
+
this.#pending.splice(0, attempted);
|
|
151
|
+
if (this.#pending.length === 0) {
|
|
152
|
+
this.#overflowReported = false;
|
|
116
153
|
}
|
|
117
154
|
};
|
|
118
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-publisher.js","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,4BAA4B,EAC5B,4BAA4B,EAC5B,kBAAkB,GAKrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAInC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAC5C,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1C,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACxC,0FAA0F;AAC1F,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAC3C,MAAM,oBAAoB,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;AACzG,MAAM,CAAC,MAAM,uCAAuC,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"session-event-publisher.js","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.js
CHANGED
|
@@ -22582,7 +22582,7 @@ import { fetch as fetch3 } from "undici";
|
|
|
22582
22582
|
// package.json
|
|
22583
22583
|
var package_default = {
|
|
22584
22584
|
name: "@moxt-ai/mobius",
|
|
22585
|
-
version: "0.0.
|
|
22585
|
+
version: "0.0.296",
|
|
22586
22586
|
description: "Mobius CLI for pairing and running local AI agent services.",
|
|
22587
22587
|
type: "module",
|
|
22588
22588
|
bin: {
|
|
@@ -90231,37 +90231,44 @@ async function runRelayConnection({
|
|
|
90231
90231
|
// src/runtime/relay/session-event-publisher.ts
|
|
90232
90232
|
import { WebSocket as WebSocket8 } from "undici";
|
|
90233
90233
|
var MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
|
|
90234
|
+
var MAX_PENDING_BYTES2 = 32 * 1024 * 1024;
|
|
90234
90235
|
var MAX_EVENT_BATCH_BYTES = 1024 * 1024;
|
|
90235
90236
|
var MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
90236
90237
|
var LOCAL_BACKPRESSURE_CLOSE_CODE = 4009;
|
|
90237
90238
|
var EMPTY_ENVELOPE_BYTES = Buffer.byteLength(JSON.stringify({ events: [], kind: SESSION_EVENT_KIND }));
|
|
90238
90239
|
var SESSION_EVENT_BATCH_WINDOW_MILLISECONDS = 100;
|
|
90239
90240
|
var RuntimeSessionEventPublisher = class {
|
|
90240
|
-
#
|
|
90241
|
-
#pendingBytes =
|
|
90241
|
+
#pending = [];
|
|
90242
|
+
#pendingBytes = 0;
|
|
90243
|
+
#overflowReported = false;
|
|
90242
90244
|
#pendingTask = null;
|
|
90243
|
-
#
|
|
90245
|
+
#connection = { kind: "disconnected" };
|
|
90244
90246
|
#timer;
|
|
90245
90247
|
constructor(timer) {
|
|
90246
90248
|
this.#timer = timer;
|
|
90247
90249
|
}
|
|
90248
90250
|
connect = (socket) => {
|
|
90249
|
-
this.
|
|
90250
|
-
|
|
90251
|
+
if (this.#connection.kind === "closed") {
|
|
90252
|
+
return;
|
|
90253
|
+
}
|
|
90254
|
+
this.#connection = { kind: "connected", socket };
|
|
90255
|
+
this.flushEvents(socket);
|
|
90251
90256
|
};
|
|
90252
90257
|
disconnect = (socket) => {
|
|
90253
|
-
if (this.#socket === socket) {
|
|
90254
|
-
this.#
|
|
90255
|
-
this.
|
|
90258
|
+
if (this.#connection.kind === "connected" && this.#connection.socket === socket) {
|
|
90259
|
+
this.#connection = { kind: "disconnected" };
|
|
90260
|
+
this.cancelFlush();
|
|
90256
90261
|
}
|
|
90257
90262
|
};
|
|
90258
90263
|
close = () => {
|
|
90259
|
-
this.#
|
|
90260
|
-
this.
|
|
90264
|
+
this.#connection = { kind: "closed" };
|
|
90265
|
+
this.cancelFlush();
|
|
90266
|
+
this.#pending.length = 0;
|
|
90267
|
+
this.#pendingBytes = 0;
|
|
90261
90268
|
};
|
|
90262
90269
|
flush = () => {
|
|
90263
|
-
if (this.#
|
|
90264
|
-
this.flushEvents(this.#socket);
|
|
90270
|
+
if (this.#connection.kind === "connected") {
|
|
90271
|
+
this.flushEvents(this.#connection.socket);
|
|
90265
90272
|
}
|
|
90266
90273
|
};
|
|
90267
90274
|
publishOperationFailure = (sessionId, requestId, code, message) => {
|
|
@@ -90271,10 +90278,11 @@ var RuntimeSessionEventPublisher = class {
|
|
|
90271
90278
|
publishInfo = (event) => this.#send(event);
|
|
90272
90279
|
publishClosed = (event) => this.#send(event);
|
|
90273
90280
|
#send = (message) => {
|
|
90274
|
-
const
|
|
90275
|
-
if (
|
|
90281
|
+
const connection = this.#connection;
|
|
90282
|
+
if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket8.OPEN) {
|
|
90276
90283
|
return;
|
|
90277
90284
|
}
|
|
90285
|
+
const socket = connection.socket;
|
|
90278
90286
|
const encoded = encodeDaemonToServiceMessage(message);
|
|
90279
90287
|
if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
|
|
90280
90288
|
socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
|
|
@@ -90286,8 +90294,7 @@ var RuntimeSessionEventPublisher = class {
|
|
|
90286
90294
|
}
|
|
90287
90295
|
};
|
|
90288
90296
|
publish = (event) => {
|
|
90289
|
-
|
|
90290
|
-
if (socket === null || socket.readyState !== WebSocket8.OPEN) {
|
|
90297
|
+
if (this.#connection.kind === "closed") {
|
|
90291
90298
|
return;
|
|
90292
90299
|
}
|
|
90293
90300
|
const bytes = Buffer.byteLength(JSON.stringify(event), "utf8") + 1;
|
|
@@ -90300,15 +90307,34 @@ var RuntimeSessionEventPublisher = class {
|
|
|
90300
90307
|
});
|
|
90301
90308
|
return;
|
|
90302
90309
|
}
|
|
90303
|
-
|
|
90304
|
-
|
|
90305
|
-
|
|
90306
|
-
|
|
90310
|
+
let batch = this.#pending.at(-1);
|
|
90311
|
+
const newBatch = batch === void 0 || batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE || batch.bytes + bytes > MAX_EVENT_BATCH_BYTES;
|
|
90312
|
+
const additionalBytes = bytes + (newBatch ? EMPTY_ENVELOPE_BYTES : 0);
|
|
90313
|
+
if (this.#pendingBytes + additionalBytes > MAX_PENDING_BYTES2) {
|
|
90314
|
+
if (!this.#overflowReported) {
|
|
90315
|
+
this.#overflowReported = true;
|
|
90316
|
+
console.warn("Live Session output exceeded the pending buffer limit", {
|
|
90317
|
+
code: "live_event_buffer_full",
|
|
90318
|
+
sessionId: event.sessionId,
|
|
90319
|
+
eventId: event.eventId,
|
|
90320
|
+
maximumBytes: MAX_PENDING_BYTES2
|
|
90321
|
+
});
|
|
90307
90322
|
}
|
|
90323
|
+
return;
|
|
90308
90324
|
}
|
|
90309
|
-
|
|
90310
|
-
|
|
90311
|
-
|
|
90325
|
+
if (batch === void 0 || newBatch) {
|
|
90326
|
+
batch = { events: [], bytes: EMPTY_ENVELOPE_BYTES };
|
|
90327
|
+
this.#pending.push(batch);
|
|
90328
|
+
}
|
|
90329
|
+
batch.events.push(event);
|
|
90330
|
+
batch.bytes += bytes;
|
|
90331
|
+
this.#pendingBytes += additionalBytes;
|
|
90332
|
+
const connection = this.#connection;
|
|
90333
|
+
if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket8.OPEN) {
|
|
90334
|
+
return;
|
|
90335
|
+
}
|
|
90336
|
+
const socket = connection.socket;
|
|
90337
|
+
if (this.#pending.length > 1 || batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE || batch.bytes >= MAX_EVENT_BATCH_BYTES) {
|
|
90312
90338
|
this.flushEvents(socket);
|
|
90313
90339
|
return;
|
|
90314
90340
|
}
|
|
@@ -90317,29 +90343,35 @@ var RuntimeSessionEventPublisher = class {
|
|
|
90317
90343
|
SESSION_EVENT_BATCH_WINDOW_MILLISECONDS
|
|
90318
90344
|
);
|
|
90319
90345
|
};
|
|
90320
|
-
|
|
90346
|
+
cancelFlush = () => {
|
|
90321
90347
|
this.#pendingTask?.cancel();
|
|
90322
90348
|
this.#pendingTask = null;
|
|
90323
|
-
this.#pendingEvents = [];
|
|
90324
|
-
this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
|
|
90325
90349
|
};
|
|
90326
90350
|
flushEvents = (socket) => {
|
|
90327
|
-
this
|
|
90328
|
-
|
|
90329
|
-
|
|
90330
|
-
this.#pendingEvents = [];
|
|
90331
|
-
this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
|
|
90332
|
-
if (events.length === 0 || this.#socket !== socket || socket.readyState !== WebSocket8.OPEN) {
|
|
90351
|
+
this.cancelFlush();
|
|
90352
|
+
const connection = this.#connection;
|
|
90353
|
+
if (connection.kind !== "connected" || connection.socket !== socket || socket.readyState !== WebSocket8.OPEN) {
|
|
90333
90354
|
return;
|
|
90334
90355
|
}
|
|
90335
|
-
|
|
90336
|
-
|
|
90337
|
-
|
|
90338
|
-
|
|
90356
|
+
let attempted = 0;
|
|
90357
|
+
for (const batch of this.#pending) {
|
|
90358
|
+
const encoded = encodeDaemonToServiceMessage({ events: batch.events, kind: SESSION_EVENT_KIND });
|
|
90359
|
+
if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
|
|
90360
|
+
socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
|
|
90361
|
+
break;
|
|
90362
|
+
}
|
|
90363
|
+
attempted += 1;
|
|
90364
|
+
this.#pendingBytes -= batch.bytes;
|
|
90365
|
+
try {
|
|
90366
|
+
socket.send(encoded);
|
|
90367
|
+
} catch {
|
|
90368
|
+
console.warn("Live Session output could not be sent", { code: "live_event_send_failed" });
|
|
90369
|
+
break;
|
|
90370
|
+
}
|
|
90339
90371
|
}
|
|
90340
|
-
|
|
90341
|
-
|
|
90342
|
-
|
|
90372
|
+
this.#pending.splice(0, attempted);
|
|
90373
|
+
if (this.#pending.length === 0) {
|
|
90374
|
+
this.#overflowReported = false;
|
|
90343
90375
|
}
|
|
90344
90376
|
};
|
|
90345
90377
|
};
|