@cendarsoss/pusher-js 8.4.13 → 8.4.15
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/CHANGELOG.md +928 -928
- package/DELTA_USAGE.md +0 -0
- package/IMPORT_GUIDE.md +0 -0
- package/bun.lock +1819 -171
- package/dist/node/pusher.js +22 -38
- package/dist/node/pusher.js.map +1 -1
- package/dist/web/pusher.mjs +22 -38
- package/dist/web/pusher.mjs.map +1 -1
- package/examples/delta-seamless-example.html +0 -0
- package/interactive/public/delta-compression.js +43 -29
- package/package.json +1 -1
- package/src/core/delta/channel_state.ts +3 -2
- package/src/core/delta/manager.ts +21 -40
- package/src/filter.ts +0 -0
- package/src/index.ts +0 -0
- package/vite.config.js +0 -0
- package/vite.config.node.js +0 -0
|
File without changes
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
constructor(channelName) {
|
|
133
133
|
this.channelName = channelName;
|
|
134
134
|
this.conflationKey = null; // e.g., "asset", "device_id"
|
|
135
|
-
this.maxMessagesPerKey = 10
|
|
135
|
+
this.maxMessagesPerKey = 30; // Increased from 10 to 30 to prevent base eviction
|
|
136
136
|
|
|
137
137
|
// Conflation key caches: Map<conflationKeyValue, Array<CachedMessage>>
|
|
138
138
|
// e.g., { "BTC": [{content: {...}, seq: 1}, ...], "ETH": [...] }
|
|
@@ -153,7 +153,9 @@
|
|
|
153
153
|
*/
|
|
154
154
|
initializeFromCacheSync(data) {
|
|
155
155
|
this.conflationKey = data.conflation_key || null;
|
|
156
|
-
|
|
156
|
+
// Force at least 30 to safely handle server's full_message_interval=10 + deltas
|
|
157
|
+
// The server sends 10 by default, which causes race conditions with eviction
|
|
158
|
+
this.maxMessagesPerKey = Math.max(data.max_messages_per_key || 10, 30);
|
|
157
159
|
this.conflationCaches.clear();
|
|
158
160
|
|
|
159
161
|
// Load all conflation group caches
|
|
@@ -178,7 +180,7 @@
|
|
|
178
180
|
}
|
|
179
181
|
|
|
180
182
|
/**
|
|
181
|
-
* Get base message for a conflation key at specific
|
|
183
|
+
* Get base message for a conflation key at specific sequence (base_index is actually sequence number)
|
|
182
184
|
*/
|
|
183
185
|
getBaseMessage(conflationKeyValue, baseIndex) {
|
|
184
186
|
if (!this.conflationKey) {
|
|
@@ -189,11 +191,26 @@
|
|
|
189
191
|
const key = conflationKeyValue || "";
|
|
190
192
|
const cache = this.conflationCaches.get(key);
|
|
191
193
|
|
|
192
|
-
if (!cache ||
|
|
194
|
+
if (!cache || cache.length === 0) {
|
|
195
|
+
console.warn("[ChannelState] No cache for conflation key:", key);
|
|
193
196
|
return null;
|
|
194
197
|
}
|
|
195
198
|
|
|
196
|
-
|
|
199
|
+
// baseIndex is actually the sequence number from the server
|
|
200
|
+
// Search for the message with matching sequence
|
|
201
|
+
const msg = cache.find((m) => m.sequence === baseIndex);
|
|
202
|
+
if (msg) {
|
|
203
|
+
return msg.content;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// If not found by sequence, log debug info
|
|
207
|
+
console.warn("[ChannelState] Could not find message with sequence", {
|
|
208
|
+
searchingFor: baseIndex,
|
|
209
|
+
cacheSize: cache.length,
|
|
210
|
+
cacheSequences: cache.map((m) => m.sequence),
|
|
211
|
+
key: key,
|
|
212
|
+
});
|
|
213
|
+
return null;
|
|
197
214
|
}
|
|
198
215
|
|
|
199
216
|
/**
|
|
@@ -877,26 +894,13 @@
|
|
|
877
894
|
const sequence = data.__delta_seq;
|
|
878
895
|
const conflationKey = data.__conflation_key;
|
|
879
896
|
|
|
880
|
-
//
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
if (channel && channel.subscribed) {
|
|
885
|
-
targetChannelName = channelName;
|
|
886
|
-
break;
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
// If no existing channel state, assume it's for the first subscribed channel
|
|
891
|
-
if (!targetChannelName) {
|
|
892
|
-
const allChannels = this.pusher.allChannels();
|
|
893
|
-
if (allChannels.length > 0) {
|
|
894
|
-
targetChannelName = allChannels[0].name;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
+
// Use the channel name passed to this function directly
|
|
898
|
+
// Previously this code incorrectly searched through channelStates.keys()
|
|
899
|
+
// instead of using the provided parameter, causing state mismatch
|
|
900
|
+
const targetChannelName = channelName;
|
|
897
901
|
|
|
898
902
|
if (!targetChannelName) {
|
|
899
|
-
this._log("
|
|
903
|
+
this._log("No channel name provided for message", {
|
|
900
904
|
eventName,
|
|
901
905
|
sequence,
|
|
902
906
|
});
|
|
@@ -912,6 +916,16 @@
|
|
|
912
916
|
this.channelStates.set(targetChannelName, channelState);
|
|
913
917
|
}
|
|
914
918
|
|
|
919
|
+
// If we receive a conflation key in the message and haven't set one yet, set it now
|
|
920
|
+
// This is important for newly created ChannelStates after resync
|
|
921
|
+
if (conflationKey !== undefined && !channelState.conflationKey) {
|
|
922
|
+
channelState.conflationKey = "token_address"; // Use a marker to indicate conflation mode
|
|
923
|
+
this._log("Initialized conflation mode for channel", {
|
|
924
|
+
channel: targetChannelName,
|
|
925
|
+
firstConflationKey: conflationKey,
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
|
|
915
929
|
// Update cache
|
|
916
930
|
if (channelState.conflationKey && conflationKey !== undefined) {
|
|
917
931
|
// Conflation mode: update specific conflation group cache
|
|
@@ -983,9 +997,9 @@
|
|
|
983
997
|
const bandwidthSavedPercent =
|
|
984
998
|
this.stats.totalBytesWithoutCompression > 0
|
|
985
999
|
? (
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1000
|
+
(bandwidthSaved / this.stats.totalBytesWithoutCompression) *
|
|
1001
|
+
100
|
|
1002
|
+
).toFixed(1)
|
|
989
1003
|
: 0;
|
|
990
1004
|
|
|
991
1005
|
this.options.onStats({
|
|
@@ -1006,9 +1020,9 @@
|
|
|
1006
1020
|
const bandwidthSavedPercent =
|
|
1007
1021
|
this.stats.totalBytesWithoutCompression > 0
|
|
1008
1022
|
? (
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1023
|
+
(bandwidthSaved / this.stats.totalBytesWithoutCompression) *
|
|
1024
|
+
100
|
|
1025
|
+
).toFixed(1)
|
|
1012
1026
|
: 0;
|
|
1013
1027
|
|
|
1014
1028
|
// Get per-channel statistics
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ export default class ChannelState {
|
|
|
22
22
|
constructor(channelName: string) {
|
|
23
23
|
this.channelName = channelName;
|
|
24
24
|
this.conflationKey = null;
|
|
25
|
-
this.maxMessagesPerKey =
|
|
25
|
+
this.maxMessagesPerKey = 30; // Increased to 30 to prevent base eviction
|
|
26
26
|
this.conflationCaches = new Map();
|
|
27
27
|
|
|
28
28
|
this.baseMessage = null;
|
|
@@ -38,7 +38,8 @@ export default class ChannelState {
|
|
|
38
38
|
*/
|
|
39
39
|
initializeFromCacheSync(data: CacheSyncData): void {
|
|
40
40
|
this.conflationKey = data.conflation_key || null;
|
|
41
|
-
|
|
41
|
+
// Force at least 30 to safely handle server's full_message_interval=10 + deltas
|
|
42
|
+
this.maxMessagesPerKey = Math.max(data.max_messages_per_key || 10, 30);
|
|
42
43
|
this.conflationCaches.clear();
|
|
43
44
|
|
|
44
45
|
if (data.states) {
|
|
@@ -33,6 +33,7 @@ export default class DeltaCompressionManager {
|
|
|
33
33
|
};
|
|
34
34
|
private availableAlgorithms: DeltaAlgorithm[];
|
|
35
35
|
private sendEventCallback: (event: string, data: any) => boolean;
|
|
36
|
+
private defaultAlgorithm: DeltaAlgorithm = 'fossil';
|
|
36
37
|
|
|
37
38
|
constructor(
|
|
38
39
|
options: DeltaOptions = {},
|
|
@@ -63,7 +64,7 @@ export default class DeltaCompressionManager {
|
|
|
63
64
|
if (this.availableAlgorithms.length === 0) {
|
|
64
65
|
Logger.warn(
|
|
65
66
|
'[DeltaCompression] No delta algorithms available. ' +
|
|
66
|
-
|
|
67
|
+
'Please include fossil-delta or vcdiff-decoder libraries.',
|
|
67
68
|
);
|
|
68
69
|
}
|
|
69
70
|
}
|
|
@@ -133,6 +134,9 @@ export default class DeltaCompressionManager {
|
|
|
133
134
|
*/
|
|
134
135
|
handleEnabled(data: any): void {
|
|
135
136
|
this.enabled = data.enabled || true;
|
|
137
|
+
if (data.algorithm) {
|
|
138
|
+
this.defaultAlgorithm = data.algorithm;
|
|
139
|
+
}
|
|
136
140
|
this.log('Delta compression enabled', data);
|
|
137
141
|
}
|
|
138
142
|
|
|
@@ -169,7 +173,7 @@ export default class DeltaCompressionManager {
|
|
|
169
173
|
const event = deltaData.event;
|
|
170
174
|
const delta = deltaData.delta;
|
|
171
175
|
const sequence = deltaData.seq;
|
|
172
|
-
const algorithm = deltaData.algorithm || 'fossil';
|
|
176
|
+
const algorithm = deltaData.algorithm || this.defaultAlgorithm || 'fossil';
|
|
173
177
|
const conflationKey = deltaData.conflation_key;
|
|
174
178
|
const baseIndex = deltaData.base_index;
|
|
175
179
|
|
|
@@ -198,43 +202,30 @@ export default class DeltaCompressionManager {
|
|
|
198
202
|
baseMessage = channelState.getBaseMessage(conflationKey, baseIndex);
|
|
199
203
|
if (!baseMessage) {
|
|
200
204
|
this.error(
|
|
201
|
-
`No base message
|
|
202
|
-
|
|
203
|
-
|
|
205
|
+
`No base message for channel ${channel}, key ${conflationKey}, index ${baseIndex}`,
|
|
206
|
+
);
|
|
207
|
+
if (this.options.debug) {
|
|
208
|
+
this.log('Current conflation cache snapshot', {
|
|
204
209
|
channel,
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
deltaSeq: sequence,
|
|
208
|
-
channelStateConflationKey: channelState.conflationKey,
|
|
209
|
-
channelStateBaseMessage: channelState.baseMessage ? 'exists' : null,
|
|
210
|
-
channelStateBaseSequence: channelState.baseSequence,
|
|
211
|
-
channelStateLastSequence: channelState.lastSequence,
|
|
212
|
-
conflationCacheKeys: Array.from(channelState.conflationCaches.keys()),
|
|
213
|
-
conflationCacheSizes: Array.from(
|
|
210
|
+
conflationKey: channelState.conflationKey,
|
|
211
|
+
cacheSizes: Array.from(
|
|
214
212
|
channelState.conflationCaches.entries(),
|
|
215
213
|
).map(([key, cache]) => ({ key, size: cache.length })),
|
|
216
|
-
}
|
|
217
|
-
|
|
214
|
+
});
|
|
215
|
+
}
|
|
218
216
|
this.requestResync(channel);
|
|
219
217
|
return null;
|
|
220
218
|
}
|
|
221
219
|
} else {
|
|
222
220
|
baseMessage = channelState.baseMessage;
|
|
223
221
|
if (!baseMessage) {
|
|
224
|
-
this.error(
|
|
225
|
-
|
|
226
|
-
{
|
|
227
|
-
path: 'legacy',
|
|
222
|
+
this.error(`No base message for channel ${channel}`);
|
|
223
|
+
if (this.options.debug) {
|
|
224
|
+
this.log('Channel state missing base', {
|
|
228
225
|
channel,
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
channelStateConflationKey: channelState.conflationKey,
|
|
233
|
-
channelStateBaseMessage: null,
|
|
234
|
-
channelStateBaseSequence: channelState.baseSequence,
|
|
235
|
-
channelStateLastSequence: channelState.lastSequence,
|
|
236
|
-
},
|
|
237
|
-
);
|
|
226
|
+
lastSequence: channelState.lastSequence,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
238
229
|
this.requestResync(channel);
|
|
239
230
|
return null;
|
|
240
231
|
}
|
|
@@ -297,20 +288,10 @@ export default class DeltaCompressionManager {
|
|
|
297
288
|
// Parse and return the reconstructed event
|
|
298
289
|
try {
|
|
299
290
|
const parsedMessage = JSON.parse(reconstructedMessage);
|
|
300
|
-
let data = parsedMessage.data || parsedMessage;
|
|
301
|
-
// Try to parse data if it's a string (Pusher protocol double-encodes data)
|
|
302
|
-
// This matches the behavior in protocol.ts decodeMessage
|
|
303
|
-
if (typeof data === 'string') {
|
|
304
|
-
try {
|
|
305
|
-
data = JSON.parse(data);
|
|
306
|
-
} catch (e) {
|
|
307
|
-
// Keep as string if not valid JSON
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
291
|
return {
|
|
311
292
|
event: event,
|
|
312
293
|
channel: channel,
|
|
313
|
-
data: data,
|
|
294
|
+
data: parsedMessage.data || parsedMessage,
|
|
314
295
|
};
|
|
315
296
|
} catch (e) {
|
|
316
297
|
// If not JSON, return as-is
|
package/src/filter.ts
CHANGED
|
File without changes
|
package/src/index.ts
CHANGED
|
File without changes
|
package/vite.config.js
CHANGED
|
File without changes
|
package/vite.config.node.js
CHANGED
|
File without changes
|