@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.
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
- this.maxMessagesPerKey = data.max_messages_per_key || 10;
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 index
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 || baseIndex >= cache.length) {
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
- return cache[baseIndex].content;
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
- // Find which channel this message belongs to by checking all subscribed channels
881
- let targetChannelName = null;
882
- for (const channelName of this.channelStates.keys()) {
883
- const channel = this.pusher.channel(channelName);
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("Cannot determine channel for message", {
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
- (bandwidthSaved / this.stats.totalBytesWithoutCompression) *
987
- 100
988
- ).toFixed(1)
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
- (bandwidthSaved / this.stats.totalBytesWithoutCompression) *
1010
- 100
1011
- ).toFixed(1)
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cendarsoss/pusher-js",
3
- "version": "8.4.13",
3
+ "version": "8.4.15",
4
4
  "description": "Pusher Channels JavaScript library for browsers, React Native, NodeJS and web workers",
5
5
  "types": "index.d.ts",
6
6
  "main": "dist/node/pusher.js",
@@ -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 = 10;
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
- this.maxMessagesPerKey = data.max_messages_per_key || 10;
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
- 'Please include fossil-delta or vcdiff-decoder libraries.',
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 (conflation path) for channel ${channel}`,
202
- {
203
- path: 'conflation',
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
- deltaConflationKey: conflationKey,
206
- deltaBaseIndex: baseIndex,
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
- `No base message (legacy path) for channel ${channel}`,
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
- deltaConflationKey: conflationKey,
230
- deltaBaseIndex: baseIndex,
231
- deltaSeq: sequence,
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
File without changes