@hydranium/client-theia 1.0.0-next.185 → 1.0.0-next.187

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 (29) hide show
  1. package/lib/browser/session-aware-connection-source.d.ts +5 -2
  2. package/lib/browser/session-aware-connection-source.d.ts.map +1 -1
  3. package/lib/browser/session-aware-connection-source.js +21 -4
  4. package/lib/browser/session-aware-connection-source.js.map +1 -1
  5. package/lib/common/connection-resilience-options.d.ts +6 -0
  6. package/lib/common/connection-resilience-options.d.ts.map +1 -1
  7. package/lib/common/framed-socket-write-buffer.d.ts +55 -3
  8. package/lib/common/framed-socket-write-buffer.d.ts.map +1 -1
  9. package/lib/common/framed-socket-write-buffer.js +111 -8
  10. package/lib/common/framed-socket-write-buffer.js.map +1 -1
  11. package/lib/common/inbound-message-sequence.d.ts +56 -0
  12. package/lib/common/inbound-message-sequence.d.ts.map +1 -0
  13. package/lib/common/inbound-message-sequence.js +98 -0
  14. package/lib/common/inbound-message-sequence.js.map +1 -0
  15. package/lib/common/index.d.ts +1 -0
  16. package/lib/common/index.d.ts.map +1 -1
  17. package/lib/common/index.js +1 -0
  18. package/lib/common/index.js.map +1 -1
  19. package/lib/node/session-bound-frontend-connection-service.d.ts +41 -0
  20. package/lib/node/session-bound-frontend-connection-service.d.ts.map +1 -1
  21. package/lib/node/session-bound-frontend-connection-service.js +98 -2
  22. package/lib/node/session-bound-frontend-connection-service.js.map +1 -1
  23. package/package.json +3 -3
  24. package/src/browser/session-aware-connection-source.ts +21 -4
  25. package/src/common/connection-resilience-options.ts +6 -0
  26. package/src/common/framed-socket-write-buffer.ts +127 -9
  27. package/src/common/inbound-message-sequence.ts +102 -0
  28. package/src/common/index.ts +1 -0
  29. package/src/node/session-bound-frontend-connection-service.ts +106 -1
@@ -58,8 +58,11 @@ export declare class SessionAwareConnectionSource extends WebSocketConnectionSou
58
58
  /** Whether a message may go out now, as opposed to waiting in the buffer. */
59
59
  protected get canSend(): boolean;
60
60
  /**
61
- * Copied from Theia apart from the `onCommit` body, because the base builds that callback inline
62
- * and exposes no narrower seam. Re-diff when the supported range moves.
61
+ * Copied from Theia apart from the duplicate check on receipt and the `onCommit` body, because
62
+ * the base builds both callbacks inline and exposes no narrower seam. Re-diff when the supported
63
+ * range moves.
64
+ *
65
+ * Called once per session, so the receive-side state starts afresh with the server's numbering.
63
66
  */
64
67
  protected createChannel(): AbstractChannel;
65
68
  /** Fires when the buffer runs out of room, so an adopter can say so rather than just stopping. */
@@ -1 +1 @@
1
- {"version":3,"file":"session-aware-connection-source.d.ts","sourceRoot":"","sources":["../../src/browser/session-aware-connection-source.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,yBAAyB,EAAE,MAAM,wDAAwD,CAAC;AAEnG,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,KAAK,eAAe,EAAqB,MAAM,4CAA4C,CAAC;AAGrG,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE3E,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EACJ,KAAK,wBAAwB,EAE7B,uBAAuB,EAGzB,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,4BAA6B,SAAQ,yBAAyB;IACxE;;;;;;OAMG;IACH,SAAS,CAAC,cAAc,UAAS;IACjC,SAAS,CAAC,wBAAwB,UAAS;IAE3C;;;;OAIG;IACH,UAAmB,qBAAqB,IAAI,IAAI,CAI/C;IAED;;;;;;OAMG;IACH,SAAS,CAAC,iBAAiB,IAAI,IAAI,CAWlC;IAED,6EAA6E;IAC7E,SAAS,KAAK,OAAO,IAAI,OAAO,CAE/B;IAED;;;OAGG;IACH,UAAmB,aAAa,IAAI,eAAe,CAwBlD;IAED,kGAAkG;IAClG,IAAI,gBAAgB,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAEtD;IAED;;;;;;;;;OASG;IACH,SAAS,KAAK,YAAY,IAAI,uBAAuB,CAMpD;CACH;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACrC,OAAO,EAAE,UAAU,CAAC,OAAO,EAC3B,MAAM,EAAE,UAAU,CAAC,MAAM,EACzB,OAAO,GAAE,2BAAgC,GACzC,OAAO,CAST"}
1
+ {"version":3,"file":"session-aware-connection-source.d.ts","sourceRoot":"","sources":["../../src/browser/session-aware-connection-source.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,yBAAyB,EAAE,MAAM,wDAAwD,CAAC;AAEnG,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,KAAK,eAAe,EAAqB,MAAM,4CAA4C,CAAC;AAGrG,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE3E,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EACJ,KAAK,wBAAwB,EAE7B,uBAAuB,EAGzB,MAAM,sCAAsC,CAAC;AAG9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,4BAA6B,SAAQ,yBAAyB;IACxE;;;;;;OAMG;IACH,SAAS,CAAC,cAAc,UAAS;IACjC,SAAS,CAAC,wBAAwB,UAAS;IAE3C;;;;OAIG;IACH,UAAmB,qBAAqB,IAAI,IAAI,CAI/C;IAED;;;;;;OAMG;IACH,SAAS,CAAC,iBAAiB,IAAI,IAAI,CAgBlC;IAED,6EAA6E;IAC7E,SAAS,KAAK,OAAO,IAAI,OAAO,CAE/B;IAED;;;;;;OAMG;IACH,UAAmB,aAAa,IAAI,eAAe,CAgClD;IAED,kGAAkG;IAClG,IAAI,gBAAgB,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAEtD;IAED;;;;;;;;;OASG;IACH,SAAS,KAAK,YAAY,IAAI,uBAAuB,CAMpD;CACH;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACrC,OAAO,EAAE,UAAU,CAAC,OAAO,EAC3B,MAAM,EAAE,UAAU,CAAC,MAAM,EACzB,OAAO,GAAE,2BAAgC,GACzC,OAAO,CAST"}
@@ -24,6 +24,7 @@ const connection_management_1 = require("@theia/core/lib/common/messaging/connec
24
24
  const inversify_1 = require("@theia/core/shared/inversify");
25
25
  const socket_write_buffer_1 = require("@theia/core/lib/common/messaging/socket-write-buffer");
26
26
  const framed_socket_write_buffer_1 = require("../common/framed-socket-write-buffer");
27
+ const inbound_message_sequence_1 = require("../common/inbound-message-sequence");
27
28
  /**
28
29
  * Sends a message only once the server has confirmed the session, and only
29
30
  * behind anything already queued.
@@ -81,19 +82,35 @@ let SessionAwareConnectionSource = class SessionAwareConnectionSource extends ws
81
82
  this.socket.on(connection_management_1.ConnectionManagementMessages.RECONNECT, (hasConnection) => {
82
83
  this.sessionResumed = hasConnection;
83
84
  });
85
+ this.socket.on(inbound_message_sequence_1.ACKNOWLEDGEMENT_EVENT, (sequence) => {
86
+ if (typeof sequence === 'number') {
87
+ this.framedBuffer.acknowledge(sequence);
88
+ }
89
+ });
84
90
  }
85
91
  /** Whether a message may go out now, as opposed to waiting in the buffer. */
86
92
  get canSend() {
87
93
  return this.socket.connected && this.sessionResumed;
88
94
  }
89
95
  /**
90
- * Copied from Theia apart from the `onCommit` body, because the base builds that callback inline
91
- * and exposes no narrower seam. Re-diff when the supported range moves.
96
+ * Copied from Theia apart from the duplicate check on receipt and the `onCommit` body, because
97
+ * the base builds both callbacks inline and exposes no narrower seam. Re-diff when the supported
98
+ * range moves.
99
+ *
100
+ * Called once per session, so the receive-side state starts afresh with the server's numbering.
92
101
  */
93
102
  createChannel() {
94
103
  const toDispose = new disposable_1.DisposableCollection();
95
- const messageHandler = (data) => {
104
+ const inbound = new inbound_message_sequence_1.InboundMessageSequence(sequence => this.socket.emit(inbound_message_sequence_1.ACKNOWLEDGEMENT_EVENT, sequence));
105
+ toDispose.push(disposable_1.Disposable.create(() => inbound.dispose()));
106
+ const messageHandler = (data, sequence) => {
96
107
  this.onIncomingMessageActivityEmitter.fire();
108
+ if (typeof sequence === 'number') {
109
+ this.framedBuffer.markPeerDeduplicates();
110
+ }
111
+ if (!inbound.accept(sequence, data.byteLength)) {
112
+ return;
113
+ }
97
114
  if (this.currentChannel) {
98
115
  // socket.io hands binary over as ArrayBuffer in the browser.
99
116
  const buffer = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
@@ -160,7 +177,7 @@ function bindConnectionResilience(isBound, rebind, options = {}) {
160
177
  return false;
161
178
  }
162
179
  // Scopes are kept as Theia declares them: one buffer per connection source, one shared socket owner.
163
- rebind(socket_write_buffer_1.SocketWriteBuffer).toDynamicValue(() => (0, framed_socket_write_buffer_1.createFramedSocketWriteBuffer)(options.bufferBytes));
180
+ rebind(socket_write_buffer_1.SocketWriteBuffer).toDynamicValue(() => (0, framed_socket_write_buffer_1.createFramedSocketWriteBuffer)(options));
164
181
  rebind(ws_connection_source_1.WebSocketConnectionSource).to(SessionAwareConnectionSource).inSingletonScope();
165
182
  return true;
166
183
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session-aware-connection-source.js","sourceRoot":"","sources":["../../src/browser/session-aware-connection-source.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-aware-connection-source.js","sourceRoot":"","sources":["../../src/browser/session-aware-connection-source.ts"],"names":[],"mappings":"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"}
@@ -20,5 +20,11 @@ export interface ConnectionResilienceOptions {
20
20
  * trades memory for tolerance here.
21
21
  */
22
22
  readonly bufferBytes?: number;
23
+ /**
24
+ * How much each side keeps of what it sent and the peer has not acknowledged
25
+ * yet, in bytes. Past it the copies are discarded and a dropped connection
26
+ * loses them, so it bounds what a peer that never acknowledges can cost.
27
+ */
28
+ readonly unacknowledgedBytes?: number;
23
29
  }
24
30
  //# sourceMappingURL=connection-resilience-options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection-resilience-options.d.ts","sourceRoot":"","sources":["../../src/common/connection-resilience-options.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAChC"}
1
+ {"version":3,"file":"connection-resilience-options.d.ts","sourceRoot":"","sources":["../../src/common/connection-resilience-options.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACxC"}
@@ -8,6 +8,7 @@
8
8
  ********************************************************************************/
9
9
  import { Emitter, type Event } from '@theia/core/lib/common/event';
10
10
  import { SocketWriteBuffer } from '@theia/core/lib/common/messaging/socket-write-buffer';
11
+ import { type ConnectionResilienceOptions } from './connection-resilience-options';
11
12
  /**
12
13
  * Prefix on every connection log line, deliberately shared by the browser and the
13
14
  * server so one pattern greps a console and a pod log at once.
@@ -19,7 +20,8 @@ export declare const CONNECTION_LOG_PREFIX = "[connection]";
19
20
  * without a connection.
20
21
  */
21
22
  export interface MessageSink {
22
- send(data: Uint8Array): void;
23
+ /** `sequence` travels as a second socket.io argument, which a reader that does not expect it ignores. */
24
+ send(data: Uint8Array, sequence: number): void;
23
25
  }
24
26
  /**
25
27
  * Reported when the buffer runs out of room. The message that did not fit is
@@ -53,6 +55,11 @@ export interface ConnectionBufferOverflow {
53
55
  * dropping something silently. The limit is settable, since the right value
54
56
  * depends on how long an outage has to survive.
55
57
  *
58
+ * Added here: every message sent is numbered and kept until the peer
59
+ * acknowledges it, and {@link flush} resends what is still unacknowledged ahead
60
+ * of the backlog. A socket whose far end died unnoticed still accepts writes, so
61
+ * a message is not delivered just because it was sent.
62
+ *
56
63
  * Logging goes to `console` rather than through a `Logger`. On the browser side
57
64
  * Theia's preloader builds this before any Output channel exists, so there is
58
65
  * nothing else to write to; the {@link CONNECTION_LOG_PREFIX} keeps the lines
@@ -71,10 +78,32 @@ export declare class FramedSocketWriteBuffer extends SocketWriteBuffer {
71
78
  * limit is never reached.
72
79
  */
73
80
  maxBytes: number;
81
+ /** Kept copies past this are discarded, so a peer that never acknowledges cannot grow them without bound. */
82
+ static readonly DEFAULT_MAX_UNACKNOWLEDGED_BYTES: number;
83
+ /**
84
+ * Separate from {@link maxBytes}, which counts only what is produced while
85
+ * the peer is away: copies kept on a healthy connection must not use up the
86
+ * room an outage needs.
87
+ */
88
+ maxUnacknowledgedBytes: number;
74
89
  protected pending: Uint8Array[];
75
90
  protected pendingBytes: number;
76
91
  protected overflowReported: boolean;
77
92
  protected readonly onOverflowEmitter: Emitter<ConnectionBufferOverflow>;
93
+ protected nextSequence: number;
94
+ /** Oldest first: {@link acknowledge} stops at the first entry the peer has not accepted. */
95
+ protected unacknowledged: {
96
+ readonly sequence: number;
97
+ readonly data: Uint8Array;
98
+ }[];
99
+ protected unacknowledgedBytes: number;
100
+ protected unacknowledgedOverflowReported: boolean;
101
+ /**
102
+ * Whether the peer drops a message it already has. One without the hardening
103
+ * applies a resent message a second time, so nothing is resent until the
104
+ * peer has shown otherwise.
105
+ */
106
+ protected peerDeduplicates: boolean;
78
107
  /** Fires once per outage when the limit is reached. */
79
108
  get onOverflow(): Event<ConnectionBufferOverflow>;
80
109
  /**
@@ -87,11 +116,34 @@ export declare class FramedSocketWriteBuffer extends SocketWriteBuffer {
87
116
  */
88
117
  sendOrQueue(socket: MessageSink | undefined, data: Uint8Array): void;
89
118
  buffer(data: Uint8Array): void;
119
+ /**
120
+ * Kept only once `send` returns: a message whose send threw stays in the
121
+ * backlog, and keeping it as well would send it again under a second number,
122
+ * which the receiver cannot recognise as a duplicate.
123
+ */
124
+ protected send(socket: MessageSink, data: Uint8Array): void;
125
+ protected keep(sequence: number, data: Uint8Array): void;
126
+ /**
127
+ * Records that the peer numbers its messages, which only a peer that also
128
+ * drops duplicates does, so resending to it is safe.
129
+ */
130
+ markPeerDeduplicates(): void;
131
+ /** Releases every kept message numbered up to `sequence`, which the peer has accepted. */
132
+ acknowledge(sequence: number): void;
133
+ /**
134
+ * Resends what the peer has not acknowledged, under the same numbers, then
135
+ * sends the backlog. Some of the resent messages may have arrived already;
136
+ * the receiver recognises them by number and drops them.
137
+ *
138
+ * Resends only to a peer known to drop duplicates, and otherwise discards the
139
+ * copies, leaving any message lost with the old socket lost.
140
+ */
90
141
  flush(socket: MessageSink): void;
91
142
  drain(): void;
92
143
  /** Whether messages are still waiting to go out. */
93
144
  get hasBacklog(): boolean;
94
145
  protected reportOverflow(): void;
146
+ /** Also discards the kept copies: a drain ends the session, and resending them would replay it into the next one. */
95
147
  protected reset(): void;
96
148
  }
97
149
  /** Named in the warning a skipped install emits, so the reader is told what to upgrade to. */
@@ -116,6 +168,6 @@ export declare function supportsConnectionResilience(isBound: (identifier: typeo
116
168
  * never sees this line has no other way to learn the guard is absent.
117
169
  */
118
170
  export declare function warnConnectionResilienceUnavailable(tier: 'frontend' | 'backend'): void;
119
- /** Builds a buffer with the given limit, or Theia's default when none is configured. */
120
- export declare function createFramedSocketWriteBuffer(maxBytes?: number): FramedSocketWriteBuffer;
171
+ /** Builds a buffer with the configured limits, or the defaults for any not configured. */
172
+ export declare function createFramedSocketWriteBuffer(options?: ConnectionResilienceOptions): FramedSocketWriteBuffer;
121
173
  //# sourceMappingURL=framed-socket-write-buffer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"framed-socket-write-buffer.d.ts","sourceRoot":"","sources":["../../src/common/framed-socket-write-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sDAAsD,CAAC;AAEzF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACzB,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACtC,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,uBAAwB,SAAQ,iBAAiB;IAC3D,gDAAgD;IAChD,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAAc;IAE/C;;;;;;;;OAQG;IACH,QAAQ,SAA6C;IAErD,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,CAAM;IACrC,SAAS,CAAC,YAAY,SAAK;IAC3B,SAAS,CAAC,gBAAgB,UAAS;IACnC,SAAS,CAAC,QAAQ,CAAC,iBAAiB,oCAA2C;IAE/E,uDAAuD;IACvD,IAAI,UAAU,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAEhD;IAED;;;;;;;OAOG;IACH,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAMnE;IAEQ,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAWtC;IAEQ,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAiCxC;IAEQ,KAAK,IAAI,IAAI,CAKrB;IAED,oDAAoD;IACpD,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,SAAS,CAAC,cAAc,IAAI,IAAI,CAW/B;IAED,SAAS,CAAC,KAAK,IAAI,IAAI,CAItB;CACH;AAED,8FAA8F;AAC9F,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,OAAO,iBAAiB,KAAK,OAAO,GAAG,OAAO,CAEhH;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,CAMtF;AAED,wFAAwF;AACxF,wBAAgB,6BAA6B,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,uBAAuB,CAMxF"}
1
+ {"version":3,"file":"framed-socket-write-buffer.d.ts","sourceRoot":"","sources":["../../src/common/framed-socket-write-buffer.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,11 @@ exports.CONNECTION_LOG_PREFIX = '[connection]';
37
37
  * dropping something silently. The limit is settable, since the right value
38
38
  * depends on how long an outage has to survive.
39
39
  *
40
+ * Added here: every message sent is numbered and kept until the peer
41
+ * acknowledges it, and {@link flush} resends what is still unacknowledged ahead
42
+ * of the backlog. A socket whose far end died unnoticed still accepts writes, so
43
+ * a message is not delivered just because it was sent.
44
+ *
40
45
  * Logging goes to `console` rather than through a `Logger`. On the browser side
41
46
  * Theia's preloader builds this before any Output channel exists, so there is
42
47
  * nothing else to write to; the {@link CONNECTION_LOG_PREFIX} keeps the lines
@@ -55,10 +60,29 @@ class FramedSocketWriteBuffer extends socket_write_buffer_1.SocketWriteBuffer {
55
60
  * limit is never reached.
56
61
  */
57
62
  maxBytes = FramedSocketWriteBuffer.DEFAULT_MAX_BYTES;
63
+ /** Kept copies past this are discarded, so a peer that never acknowledges cannot grow them without bound. */
64
+ static DEFAULT_MAX_UNACKNOWLEDGED_BYTES = 1024 * 1024;
65
+ /**
66
+ * Separate from {@link maxBytes}, which counts only what is produced while
67
+ * the peer is away: copies kept on a healthy connection must not use up the
68
+ * room an outage needs.
69
+ */
70
+ maxUnacknowledgedBytes = FramedSocketWriteBuffer.DEFAULT_MAX_UNACKNOWLEDGED_BYTES;
58
71
  pending = [];
59
72
  pendingBytes = 0;
60
73
  overflowReported = false;
61
74
  onOverflowEmitter = new event_1.Emitter();
75
+ nextSequence = 1;
76
+ /** Oldest first: {@link acknowledge} stops at the first entry the peer has not accepted. */
77
+ unacknowledged = [];
78
+ unacknowledgedBytes = 0;
79
+ unacknowledgedOverflowReported = false;
80
+ /**
81
+ * Whether the peer drops a message it already has. One without the hardening
82
+ * applies a resent message a second time, so nothing is resent until the
83
+ * peer has shown otherwise.
84
+ */
85
+ peerDeduplicates = false;
62
86
  /** Fires once per outage when the limit is reached. */
63
87
  get onOverflow() {
64
88
  return this.onOverflowEmitter.event;
@@ -73,7 +97,7 @@ class FramedSocketWriteBuffer extends socket_write_buffer_1.SocketWriteBuffer {
73
97
  */
74
98
  sendOrQueue(socket, data) {
75
99
  if (socket && !this.hasBacklog) {
76
- socket.send(data);
100
+ this.send(socket, data);
77
101
  }
78
102
  else {
79
103
  this.buffer(data);
@@ -91,7 +115,73 @@ class FramedSocketWriteBuffer extends socket_write_buffer_1.SocketWriteBuffer {
91
115
  console.info(`${exports.CONNECTION_LOG_PREFIX} buffering messages, the peer is disconnected`);
92
116
  }
93
117
  }
118
+ /**
119
+ * Kept only once `send` returns: a message whose send threw stays in the
120
+ * backlog, and keeping it as well would send it again under a second number,
121
+ * which the receiver cannot recognise as a duplicate.
122
+ */
123
+ send(socket, data) {
124
+ const sequence = this.nextSequence++;
125
+ socket.send(data, sequence);
126
+ this.keep(sequence, data);
127
+ }
128
+ keep(sequence, data) {
129
+ if (this.unacknowledgedBytes + data.byteLength > this.maxUnacknowledgedBytes) {
130
+ // Said only to a peer known to acknowledge: one without the hardening never does, and
131
+ // nothing would be resent to it anyway.
132
+ if (this.peerDeduplicates && !this.unacknowledgedOverflowReported) {
133
+ this.unacknowledgedOverflowReported = true;
134
+ console.warn(`${exports.CONNECTION_LOG_PREFIX} the peer has not acknowledged ${this.unacknowledged.length} message(s), ` +
135
+ `${this.unacknowledgedBytes} bytes; discarding their copies, so a connection dropped now loses them`);
136
+ }
137
+ this.unacknowledged = [];
138
+ this.unacknowledgedBytes = 0;
139
+ return;
140
+ }
141
+ // Not copied: a committed write buffer hands over a fresh array and is disposed.
142
+ this.unacknowledged.push({ sequence, data });
143
+ this.unacknowledgedBytes += data.byteLength;
144
+ }
145
+ /**
146
+ * Records that the peer numbers its messages, which only a peer that also
147
+ * drops duplicates does, so resending to it is safe.
148
+ */
149
+ markPeerDeduplicates() {
150
+ this.peerDeduplicates = true;
151
+ }
152
+ /** Releases every kept message numbered up to `sequence`, which the peer has accepted. */
153
+ acknowledge(sequence) {
154
+ this.peerDeduplicates = true;
155
+ let index = 0;
156
+ while (index < this.unacknowledged.length && this.unacknowledged[index].sequence <= sequence) {
157
+ this.unacknowledgedBytes -= this.unacknowledged[index].data.byteLength;
158
+ index++;
159
+ }
160
+ if (index > 0) {
161
+ this.unacknowledged = this.unacknowledged.slice(index);
162
+ }
163
+ }
164
+ /**
165
+ * Resends what the peer has not acknowledged, under the same numbers, then
166
+ * sends the backlog. Some of the resent messages may have arrived already;
167
+ * the receiver recognises them by number and drops them.
168
+ *
169
+ * Resends only to a peer known to drop duplicates, and otherwise discards the
170
+ * copies, leaving any message lost with the old socket lost.
171
+ */
94
172
  flush(socket) {
173
+ if (this.peerDeduplicates) {
174
+ for (const { sequence, data } of this.unacknowledged) {
175
+ socket.send(data, sequence);
176
+ }
177
+ if (this.unacknowledged.length > 0) {
178
+ console.info(`${exports.CONNECTION_LOG_PREFIX} resent ${this.unacknowledged.length} unacknowledged message(s), ${this.unacknowledgedBytes} bytes`);
179
+ }
180
+ }
181
+ else {
182
+ this.unacknowledged = [];
183
+ this.unacknowledgedBytes = 0;
184
+ }
95
185
  if (this.pending.length === 0) {
96
186
  return;
97
187
  }
@@ -105,7 +195,7 @@ class FramedSocketWriteBuffer extends socket_write_buffer_1.SocketWriteBuffer {
105
195
  try {
106
196
  while (index < this.pending.length) {
107
197
  const message = this.pending[index];
108
- socket.send(message);
198
+ this.send(socket, message);
109
199
  index++;
110
200
  this.pendingBytes -= message.byteLength;
111
201
  }
@@ -125,8 +215,9 @@ class FramedSocketWriteBuffer extends socket_write_buffer_1.SocketWriteBuffer {
125
215
  console.info(`${exports.CONNECTION_LOG_PREFIX} sent ${count} buffered message(s), ${bytes} bytes`);
126
216
  }
127
217
  drain() {
128
- if (this.pending.length > 0) {
129
- console.warn(`${exports.CONNECTION_LOG_PREFIX} discarded ${this.pending.length} buffered message(s), ${this.pendingBytes} bytes`);
218
+ if (this.pending.length > 0 || this.unacknowledged.length > 0) {
219
+ console.warn(`${exports.CONNECTION_LOG_PREFIX} discarded ${this.pending.length} buffered message(s), ${this.pendingBytes} bytes, ` +
220
+ `and ${this.unacknowledged.length} sent but unacknowledged, ${this.unacknowledgedBytes} bytes`);
130
221
  }
131
222
  this.reset();
132
223
  }
@@ -144,10 +235,16 @@ class FramedSocketWriteBuffer extends socket_write_buffer_1.SocketWriteBuffer {
144
235
  'this message is rejected, and so is every further one until the peer returns');
145
236
  this.onOverflowEmitter.fire(overflow);
146
237
  }
238
+ /** Also discards the kept copies: a drain ends the session, and resending them would replay it into the next one. */
147
239
  reset() {
148
240
  this.pending = [];
149
241
  this.pendingBytes = 0;
150
242
  this.overflowReported = false;
243
+ this.nextSequence = 1;
244
+ this.unacknowledged = [];
245
+ this.unacknowledgedBytes = 0;
246
+ this.unacknowledgedOverflowReported = false;
247
+ this.peerDeduplicates = false;
151
248
  }
152
249
  }
153
250
  exports.FramedSocketWriteBuffer = FramedSocketWriteBuffer;
@@ -179,12 +276,18 @@ function warnConnectionResilienceUnavailable(tier) {
179
276
  `socket write buffer (needs ${exports.REQUIRED_THEIA_HINT}). Theia's own behaviour is left in place, which can lose or ` +
180
277
  'reorder messages when a socket drops and reconnects.');
181
278
  }
182
- /** Builds a buffer with the given limit, or Theia's default when none is configured. */
183
- function createFramedSocketWriteBuffer(maxBytes) {
279
+ /** Builds a buffer with the configured limits, or the defaults for any not configured. */
280
+ function createFramedSocketWriteBuffer(options = {}) {
184
281
  const buffer = new FramedSocketWriteBuffer();
185
- if (typeof maxBytes === 'number' && maxBytes > 0) {
186
- buffer.maxBytes = maxBytes;
282
+ if (isPositive(options.bufferBytes)) {
283
+ buffer.maxBytes = options.bufferBytes;
284
+ }
285
+ if (isPositive(options.unacknowledgedBytes)) {
286
+ buffer.maxUnacknowledgedBytes = options.unacknowledgedBytes;
187
287
  }
188
288
  return buffer;
189
289
  }
290
+ function isPositive(value) {
291
+ return typeof value === 'number' && value > 0;
292
+ }
190
293
  //# sourceMappingURL=framed-socket-write-buffer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"framed-socket-write-buffer.js","sourceRoot":"","sources":["../../src/common/framed-socket-write-buffer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"framed-socket-write-buffer.js","sourceRoot":"","sources":["../../src/common/framed-socket-write-buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ /** The socket.io event that carries the highest message number a side has accepted. */
10
+ export declare const ACKNOWLEDGEMENT_EVENT = "hydranium:ack";
11
+ /**
12
+ * What one side has received on a session: drops a message it already accepted
13
+ * and acknowledges the rest.
14
+ *
15
+ * The peer resends everything unacknowledged when a session resumes, because it
16
+ * cannot tell which of its messages died with the old socket, so every resumed
17
+ * session can repeat messages already delivered. Delivering one twice corrupts
18
+ * anything applied by position, just as losing one does.
19
+ *
20
+ * Acknowledges once enough has arrived, and otherwise after a short delay. A
21
+ * timer alone is not enough: a background tab throttles timers, and the peer
22
+ * holds every unacknowledged message until the acknowledgement arrives. The
23
+ * first message of a session is acknowledged at once, because the peer resends
24
+ * nothing until an acknowledgement shows it may.
25
+ *
26
+ * Belongs to one session. A new session numbers from the start again, so it
27
+ * needs a new instance.
28
+ */
29
+ export declare class InboundMessageSequence {
30
+ protected readonly sendAcknowledgement: (sequence: number) => void;
31
+ static readonly ACKNOWLEDGE_AFTER_MESSAGES = 64;
32
+ static readonly ACKNOWLEDGE_AFTER_BYTES: number;
33
+ static readonly ACKNOWLEDGE_DELAY_MS = 100;
34
+ protected lastAccepted: number;
35
+ protected messagesSinceAcknowledgement: number;
36
+ protected bytesSinceAcknowledgement: number;
37
+ protected acknowledgementTimer: ReturnType<typeof setTimeout> | undefined;
38
+ constructor(sendAcknowledgement: (sequence: number) => void);
39
+ /**
40
+ * Whether to deliver a message that arrived with `sequence`.
41
+ *
42
+ * A message without a number comes from a peer that does not number them,
43
+ * and is delivered as it is. A duplicate is still acknowledged: the peer
44
+ * resent it because an earlier acknowledgement was lost, and keeps it until
45
+ * one arrives.
46
+ *
47
+ * A skipped number is delivered past, with a warning: the skipped messages
48
+ * are lost, and this is the one place that can tell.
49
+ */
50
+ accept(sequence: unknown, bytes: number): boolean;
51
+ /** Sends the acknowledgement now rather than waiting for more traffic. */
52
+ acknowledge(): void;
53
+ dispose(): void;
54
+ protected cancelTimer(): void;
55
+ }
56
+ //# sourceMappingURL=inbound-message-sequence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-message-sequence.d.ts","sourceRoot":"","sources":["../../src/common/inbound-message-sequence.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,uFAAuF;AACvF,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,sBAAsB;IAUpB,SAAS,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI;IAT9E,MAAM,CAAC,QAAQ,CAAC,0BAA0B,MAAM;IAChD,MAAM,CAAC,QAAQ,CAAC,uBAAuB,SAAa;IACpD,MAAM,CAAC,QAAQ,CAAC,oBAAoB,OAAO;IAE3C,SAAS,CAAC,YAAY,SAAK;IAC3B,SAAS,CAAC,4BAA4B,SAAK;IAC3C,SAAS,CAAC,yBAAyB,SAAK;IACxC,SAAS,CAAC,oBAAoB,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAAC;IAE1E,YAA+B,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EAAI;IAElF;;;;;;;;;;OAUG;IACH,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CA4BhD;IAED,0EAA0E;IAC1E,WAAW,IAAI,IAAI,CAKlB;IAED,OAAO,IAAI,IAAI,CAEd;IAED,SAAS,CAAC,WAAW,IAAI,IAAI,CAG5B;CACH"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 EclipseSource and others.
4
+ *
5
+ * This program and the accompanying materials are made available under the
6
+ * terms of the MIT License which is available in the project root.
7
+ *
8
+ * SPDX-License-Identifier: MIT
9
+ ********************************************************************************/
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.InboundMessageSequence = exports.ACKNOWLEDGEMENT_EVENT = void 0;
12
+ const framed_socket_write_buffer_1 = require("./framed-socket-write-buffer");
13
+ /** The socket.io event that carries the highest message number a side has accepted. */
14
+ exports.ACKNOWLEDGEMENT_EVENT = 'hydranium:ack';
15
+ /**
16
+ * What one side has received on a session: drops a message it already accepted
17
+ * and acknowledges the rest.
18
+ *
19
+ * The peer resends everything unacknowledged when a session resumes, because it
20
+ * cannot tell which of its messages died with the old socket, so every resumed
21
+ * session can repeat messages already delivered. Delivering one twice corrupts
22
+ * anything applied by position, just as losing one does.
23
+ *
24
+ * Acknowledges once enough has arrived, and otherwise after a short delay. A
25
+ * timer alone is not enough: a background tab throttles timers, and the peer
26
+ * holds every unacknowledged message until the acknowledgement arrives. The
27
+ * first message of a session is acknowledged at once, because the peer resends
28
+ * nothing until an acknowledgement shows it may.
29
+ *
30
+ * Belongs to one session. A new session numbers from the start again, so it
31
+ * needs a new instance.
32
+ */
33
+ class InboundMessageSequence {
34
+ sendAcknowledgement;
35
+ static ACKNOWLEDGE_AFTER_MESSAGES = 64;
36
+ static ACKNOWLEDGE_AFTER_BYTES = 32 * 1024;
37
+ static ACKNOWLEDGE_DELAY_MS = 100;
38
+ lastAccepted = 0;
39
+ messagesSinceAcknowledgement = 0;
40
+ bytesSinceAcknowledgement = 0;
41
+ acknowledgementTimer;
42
+ constructor(sendAcknowledgement) {
43
+ this.sendAcknowledgement = sendAcknowledgement;
44
+ }
45
+ /**
46
+ * Whether to deliver a message that arrived with `sequence`.
47
+ *
48
+ * A message without a number comes from a peer that does not number them,
49
+ * and is delivered as it is. A duplicate is still acknowledged: the peer
50
+ * resent it because an earlier acknowledgement was lost, and keeps it until
51
+ * one arrives.
52
+ *
53
+ * A skipped number is delivered past, with a warning: the skipped messages
54
+ * are lost, and this is the one place that can tell.
55
+ */
56
+ accept(sequence, bytes) {
57
+ if (typeof sequence !== 'number') {
58
+ return true;
59
+ }
60
+ const isFirst = this.lastAccepted === 0;
61
+ const isNew = sequence > this.lastAccepted;
62
+ if (isNew) {
63
+ if (sequence > this.lastAccepted + 1) {
64
+ const missing = sequence - this.lastAccepted - 1;
65
+ console.warn(`${framed_socket_write_buffer_1.CONNECTION_LOG_PREFIX} lost ${missing} message(s), numbered ${this.lastAccepted + 1} to ${sequence - 1}; ` +
66
+ 'they never arrived and nothing will resend them');
67
+ }
68
+ this.lastAccepted = sequence;
69
+ }
70
+ this.messagesSinceAcknowledgement++;
71
+ this.bytesSinceAcknowledgement += bytes;
72
+ if (isFirst ||
73
+ this.messagesSinceAcknowledgement >= InboundMessageSequence.ACKNOWLEDGE_AFTER_MESSAGES ||
74
+ this.bytesSinceAcknowledgement >= InboundMessageSequence.ACKNOWLEDGE_AFTER_BYTES) {
75
+ this.acknowledge();
76
+ }
77
+ else {
78
+ this.acknowledgementTimer ??= setTimeout(() => this.acknowledge(), InboundMessageSequence.ACKNOWLEDGE_DELAY_MS);
79
+ }
80
+ return isNew;
81
+ }
82
+ /** Sends the acknowledgement now rather than waiting for more traffic. */
83
+ acknowledge() {
84
+ this.cancelTimer();
85
+ this.messagesSinceAcknowledgement = 0;
86
+ this.bytesSinceAcknowledgement = 0;
87
+ this.sendAcknowledgement(this.lastAccepted);
88
+ }
89
+ dispose() {
90
+ this.cancelTimer();
91
+ }
92
+ cancelTimer() {
93
+ clearTimeout(this.acknowledgementTimer);
94
+ this.acknowledgementTimer = undefined;
95
+ }
96
+ }
97
+ exports.InboundMessageSequence = InboundMessageSequence;
98
+ //# sourceMappingURL=inbound-message-sequence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-message-sequence.js","sourceRoot":"","sources":["../../src/common/inbound-message-sequence.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAElF,6EAAqE;AAErE,uFAAuF;AAC1E,QAAA,qBAAqB,GAAG,eAAe,CAAC;AAErD;;;;;;;;;;;;;;;;;GAiBG;AACH;IAUkC,mBAAmB;IATlD,MAAM,CAAU,0BAA0B,GAAG,EAAE,CAAC;IAChD,MAAM,CAAU,uBAAuB,GAAG,EAAE,GAAG,IAAI,CAAC;IACpD,MAAM,CAAU,oBAAoB,GAAG,GAAG,CAAC;IAEjC,YAAY,GAAG,CAAC,CAAC;IACjB,4BAA4B,GAAG,CAAC,CAAC;IACjC,yBAAyB,GAAG,CAAC,CAAC;IAC9B,oBAAoB,CAA4C;IAE1E,YAA+B,mBAA+C;mCAA/C,mBAAmB;IAA+B,CAAC;IAElF;;;;;;;;;;OAUG;IACH,MAAM,CAAC,QAAiB,EAAE,KAAa;QACpC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC;QACf,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC;QAC3C,IAAI,KAAK,EAAE,CAAC;YACT,IAAI,QAAQ,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;gBACjD,OAAO,CAAC,IAAI,CACT,GAAG,kDAAqB,SAAS,OAAO,yBAAyB,IAAI,CAAC,YAAY,GAAG,CAAC,OAAO,QAAQ,GAAG,CAAC,IAAI;oBAC1G,iDAAiD,CACtD,CAAC;YACL,CAAC;YACD,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,4BAA4B,EAAE,CAAC;QACpC,IAAI,CAAC,yBAAyB,IAAI,KAAK,CAAC;QACxC,IACG,OAAO;YACP,IAAI,CAAC,4BAA4B,IAAI,sBAAsB,CAAC,0BAA0B;YACtF,IAAI,CAAC,yBAAyB,IAAI,sBAAsB,CAAC,uBAAuB,EACjF,CAAC;YACA,IAAI,CAAC,WAAW,EAAE,CAAC;QACtB,CAAC;aAAM,CAAC;YACL,IAAI,CAAC,oBAAoB,KAAK,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;QACnH,CAAC;QACD,OAAO,KAAK,CAAC;IAChB,CAAC;IAED,0EAA0E;IAC1E,WAAW;QACR,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,4BAA4B,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC,yBAAyB,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO;QACJ,IAAI,CAAC,WAAW,EAAE,CAAC;IACtB,CAAC;IAES,WAAW;QAClB,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACxC,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC;IACzC,CAAC;CACH"}
@@ -7,6 +7,7 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
  export * from './framed-socket-write-buffer';
10
+ export * from './inbound-message-sequence';
10
11
  export * from './connection-resilience-options';
11
12
  export * from './clock';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAKlF,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAKlF,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,SAAS,CAAC"}
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  // bind for their own side, such as the buffer for each half of the socket.
27
27
  // Kept out of both tier barrels for that reason.
28
28
  __exportStar(require("./framed-socket-write-buffer"), exports);
29
+ __exportStar(require("./inbound-message-sequence"), exports);
29
30
  __exportStar(require("./connection-resilience-options"), exports);
30
31
  __exportStar(require("./clock"), exports);
31
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,4EAA4E;AAC5E,2EAA2E;AAC3E,iDAAiD;AACjD,+DAA6C;AAC7C,kEAAgD;AAChD,0CAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,4EAA4E;AAC5E,2EAA2E;AAC3E,iDAAiD;AACjD,+DAA6C;AAC7C,6DAA2C;AAC3C,kEAAgD;AAChD,0CAAwB"}