bunnyquery 1.9.4 → 1.9.6

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/bunnyquery.js CHANGED
@@ -2204,6 +2204,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
2204
2204
  const fetch2 = getChatHistory;
2205
2205
  const bgQueue = bgIndexingQueueName(params.userId, params.service);
2206
2206
  const base = { service: params.service, owner: params.owner, platform: params.platform };
2207
+ const surfaceScope = params.scopeSurfaceToQueue && params.userId ? { queue: params.userId, queue_exact: true } : { queue_exclude: bgQueue };
2207
2208
  const fetchMore = !!(fetchOptions && fetchOptions.fetchMore);
2208
2209
  const limit = fetchOptions && fetchOptions.limit;
2209
2210
  const firstLoad = !splitHistoryStates[key];
@@ -2231,13 +2232,13 @@ Index the REMAINING windows - one record per row/item, looking at any page image
2231
2232
  } else {
2232
2233
  const sOpts = { fetchMore };
2233
2234
  if (limit) sOpts.limit = limit;
2234
- let s = await fetch2({ ...base, queue_exclude: bgQueue }, sOpts);
2235
+ let s = await fetch2({ ...base, ...surfaceScope }, sOpts);
2235
2236
  let hops = 0;
2236
2237
  while (s && !s.endOfList && !(s.list || []).length && hops < SURFACE_EMPTY_MAX_PAGES) {
2237
2238
  hops++;
2238
2239
  const nOpts = { fetchMore: true };
2239
2240
  if (limit) nOpts.limit = limit;
2240
- s = await fetch2({ ...base, queue_exclude: bgQueue }, nOpts);
2241
+ s = await fetch2({ ...base, ...surfaceScope }, nOpts);
2241
2242
  }
2242
2243
  state.pendingSurface = {
2243
2244
  list: s && Array.isArray(s.list) ? s.list : [],
@@ -2370,6 +2371,14 @@ Index the REMAINING windows - one record per row/item, looking at any page image
2370
2371
  firstLoad
2371
2372
  };
2372
2373
  }
2374
+ function chatCacheKey(projectId, platform, userId) {
2375
+ if (!projectId || platform === "none") return "";
2376
+ return projectId + "#" + platform + "#" + (userId || "");
2377
+ }
2378
+ function indexScopeKey(projectId, platform) {
2379
+ if (!projectId || platform === "none") return "";
2380
+ return projectId + "#" + platform;
2381
+ }
2373
2382
  function mapHistoryListToMessages(list, platform, opts) {
2374
2383
  var mapped = [], runningItemIds = [];
2375
2384
  var extractAssistantText = platform === "openai" ? extractOpenAIText : extractClaudeText;
@@ -2456,7 +2465,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
2456
2465
  }
2457
2466
  });
2458
2467
  if (opts.projectId) {
2459
- var ownerKey = opts.projectId + "#" + platform;
2468
+ var ownerKey = chatCacheKey(opts.projectId, platform, opts.userId);
2460
2469
  for (var oi = 0; oi < mapped.length; oi++) mapped[oi]._ownerKey = ownerKey;
2461
2470
  }
2462
2471
  return { messages: mapped, runningItemIds };
@@ -2983,7 +2992,8 @@ Index the REMAINING windows - one record per row/item, looking at any page image
2983
2992
  /** Storage paths are project-relative, and one ChatSession serves every
2984
2993
  * project, so a claim has to be scoped the way a stop is (_indexKeyOf). */
2985
2994
  _indexClaimKey(storagePath) {
2986
- return this.getHistoryCacheKey() + "|" + storagePath;
2995
+ var id = this.host.getIdentity();
2996
+ return indexScopeKey(id.projectId, id.platform) + "|" + storagePath;
2987
2997
  }
2988
2998
  /**
2989
2999
  * Take this file's indexing slot, or report that someone already has it.
@@ -3425,8 +3435,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
3425
3435
  */
3426
3436
  getHistoryCacheKey() {
3427
3437
  var id = this.host.getIdentity();
3428
- if (!id.projectId || id.platform === "none") return "";
3429
- return id.projectId + "#" + id.platform + "#" + (id.userId || "");
3438
+ return chatCacheKey(id.projectId, id.platform, id.userId);
3430
3439
  }
3431
3440
  /** Re-apply memoized hydrated texts onto freshly-mapped messages. Both
3432
3441
  * clients call this right after their mapper runs (loadHistory does it
@@ -3976,7 +3985,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
3976
3985
  }
3977
3986
  if (stageId) delete this._liveStages[stageId];
3978
3987
  var llmComposed = composedForLlm || composed;
3979
- var key = !id.projectId ? "" : id.projectId + "#" + id.platform;
3988
+ var key = chatCacheKey(id.projectId, id.platform, id.userId);
3980
3989
  var offChat = !!key && key !== this.getHistoryCacheKey();
3981
3990
  var isQueuedSend = !offChat && (useBgQueue || this.state.sending || this.state.messages.some(function(m) {
3982
3991
  return (m.isPending || m.isPendingQueued) && !m.isBackgroundTask && !m._useBgQueue;
@@ -4542,7 +4551,8 @@ Index the REMAINING windows - one record per row/item, looking at any page image
4542
4551
  cancelIndexingGroup(group) {
4543
4552
  var self = this;
4544
4553
  if (!group || !group.key) return;
4545
- var scoped = this.getHistoryCacheKey() + "|" + group.key;
4554
+ var idn = this.host.getIdentity();
4555
+ var scoped = indexScopeKey(idn.projectId, idn.platform) + "|" + group.key;
4546
4556
  this.cancelledIndexKeys.add(scoped);
4547
4557
  if (!group.finished) {
4548
4558
  var stoppedIds = {};
@@ -5010,7 +5020,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
5010
5020
  if (!entry) return "";
5011
5021
  var file = entry.storagePath || entry.filename;
5012
5022
  if (!file) return "";
5013
- return entry.projectId + "#" + entry.platform + "|" + file;
5023
+ return indexScopeKey(entry.projectId, entry.platform) + "|" + file;
5014
5024
  }
5015
5025
  /**
5016
5026
  * Reconcile the bg queue with the files the user has stopped.
@@ -5537,7 +5547,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
5537
5547
  loadHistory(fetchMore, token) {
5538
5548
  var self = this;
5539
5549
  var id = this.host.getIdentity();
5540
- var loadKey = !id.projectId || id.platform === "none" ? "" : id.projectId + "#" + id.platform;
5550
+ var loadKey = chatCacheKey(id.projectId, id.platform, id.userId);
5541
5551
  if (token === void 0) token = this.state.gateRefreshToken;
5542
5552
  if (this.state.loadingHistory && this.state.historyRequestToken === token || id.platform === "none" || !id.projectId) {
5543
5553
  return Promise.resolve();
@@ -5556,7 +5566,17 @@ Index the REMAINING windows - one record per row/item, looking at any page image
5556
5566
  if (fetchMore && this.state.historyStartKeyHistory.length) options.startKeyHistory = this.state.historyStartKeyHistory.slice();
5557
5567
  if (!fetchMore) options.deferBg = true;
5558
5568
  var fetchHistory = function() {
5559
- return getSplitChatHistory({ service: projectId, owner, platform, userId: id.userId }, options);
5569
+ return getSplitChatHistory({
5570
+ service: projectId,
5571
+ owner,
5572
+ platform,
5573
+ userId: id.userId,
5574
+ // An anonymous visitor's history is scoped server side by
5575
+ // ip + "(" + user_agent + ")", which two devices behind one NAT
5576
+ // share. Read this device's own queue instead. See
5577
+ // scopeSurfaceToQueue.
5578
+ scopeSurfaceToQueue: !!id.anonymous
5579
+ }, options);
5560
5580
  };
5561
5581
  return Promise.resolve().then(fetchHistory).catch(function(err) {
5562
5582
  if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
@@ -5578,6 +5598,10 @@ Index the REMAINING windows - one record per row/item, looking at any page image
5578
5598
  var mapped = mapHistoryListToMessages(list, platform, {
5579
5599
  clearedAt: self.host.getClearedAt(),
5580
5600
  projectId: id.projectId,
5601
+ // So the `_ownerKey` stamped on server history matches loadKey and
5602
+ // the cache key. Without it every mapped bubble carries a
5603
+ // two-segment stamp that no comparison can ever match.
5604
+ userId: id.userId,
5581
5605
  formatIndexingLabel: self.host.formatIndexingLabel
5582
5606
  }).messages;
5583
5607
  self.applyHydratedBodies(mapped);
@@ -5786,6 +5810,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
5786
5810
  var m2 = mapHistoryListToMessages(sorted, platform, {
5787
5811
  clearedAt: self.host.getClearedAt(),
5788
5812
  projectId: id.projectId,
5813
+ userId: id.userId,
5789
5814
  formatIndexingLabel: self.host.formatIndexingLabel
5790
5815
  }).messages;
5791
5816
  self.applyHydratedBodies(m2);
@@ -6578,7 +6603,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
6578
6603
  (function() {
6579
6604
  var MCP_PROD = "https://mcp.broadwayinc.computer";
6580
6605
  var MCP_DEV = "https://mcp-dev.broadwayinc.computer";
6581
- var BQ_VERSION = "1.9.4" ;
6606
+ var BQ_VERSION = "1.9.6" ;
6582
6607
  var ATTACHMENT_URL_EXPIRES_SECONDS = 600;
6583
6608
  var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
6584
6609
  var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
package/dist/engine.cjs CHANGED
@@ -2346,6 +2346,7 @@ async function _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock
2346
2346
  const fetch = _fetchImpl || getChatHistory;
2347
2347
  const bgQueue = bgIndexingQueueName(params.userId, params.service);
2348
2348
  const base = { service: params.service, owner: params.owner, platform: params.platform };
2349
+ const surfaceScope = params.scopeSurfaceToQueue && params.userId ? { queue: params.userId, queue_exact: true } : { queue_exclude: bgQueue };
2349
2350
  const fetchMore = !!(fetchOptions && fetchOptions.fetchMore);
2350
2351
  const limit = fetchOptions && fetchOptions.limit;
2351
2352
  const firstLoad = !splitHistoryStates[key];
@@ -2373,13 +2374,13 @@ async function _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock
2373
2374
  } else {
2374
2375
  const sOpts = { fetchMore };
2375
2376
  if (limit) sOpts.limit = limit;
2376
- let s = await fetch({ ...base, queue_exclude: bgQueue }, sOpts);
2377
+ let s = await fetch({ ...base, ...surfaceScope }, sOpts);
2377
2378
  let hops = 0;
2378
2379
  while (s && !s.endOfList && !(s.list || []).length && hops < SURFACE_EMPTY_MAX_PAGES) {
2379
2380
  hops++;
2380
2381
  const nOpts = { fetchMore: true };
2381
2382
  if (limit) nOpts.limit = limit;
2382
- s = await fetch({ ...base, queue_exclude: bgQueue }, nOpts);
2383
+ s = await fetch({ ...base, ...surfaceScope }, nOpts);
2383
2384
  }
2384
2385
  state.pendingSurface = {
2385
2386
  list: s && Array.isArray(s.list) ? s.list : [],
@@ -2512,6 +2513,14 @@ async function _getSplitChatHistoryLocked(key, params, fetchOptions, releaseLock
2512
2513
  firstLoad
2513
2514
  };
2514
2515
  }
2516
+ function chatCacheKey(projectId, platform, userId) {
2517
+ if (!projectId || platform === "none") return "";
2518
+ return projectId + "#" + platform + "#" + (userId || "");
2519
+ }
2520
+ function indexScopeKey(projectId, platform) {
2521
+ if (!projectId || platform === "none") return "";
2522
+ return projectId + "#" + platform;
2523
+ }
2515
2524
  function mapHistoryListToMessages(list, platform, opts) {
2516
2525
  var mapped = [], runningItemIds = [];
2517
2526
  var extractAssistantText = platform === "openai" ? extractOpenAIText : extractClaudeText;
@@ -2598,7 +2607,7 @@ function mapHistoryListToMessages(list, platform, opts) {
2598
2607
  }
2599
2608
  });
2600
2609
  if (opts.projectId) {
2601
- var ownerKey = opts.projectId + "#" + platform;
2610
+ var ownerKey = chatCacheKey(opts.projectId, platform, opts.userId);
2602
2611
  for (var oi = 0; oi < mapped.length; oi++) mapped[oi]._ownerKey = ownerKey;
2603
2612
  }
2604
2613
  return { messages: mapped, runningItemIds };
@@ -3125,7 +3134,8 @@ var ChatSession = class {
3125
3134
  /** Storage paths are project-relative, and one ChatSession serves every
3126
3135
  * project, so a claim has to be scoped the way a stop is (_indexKeyOf). */
3127
3136
  _indexClaimKey(storagePath) {
3128
- return this.getHistoryCacheKey() + "|" + storagePath;
3137
+ var id = this.host.getIdentity();
3138
+ return indexScopeKey(id.projectId, id.platform) + "|" + storagePath;
3129
3139
  }
3130
3140
  /**
3131
3141
  * Take this file's indexing slot, or report that someone already has it.
@@ -3567,8 +3577,7 @@ var ChatSession = class {
3567
3577
  */
3568
3578
  getHistoryCacheKey() {
3569
3579
  var id = this.host.getIdentity();
3570
- if (!id.projectId || id.platform === "none") return "";
3571
- return id.projectId + "#" + id.platform + "#" + (id.userId || "");
3580
+ return chatCacheKey(id.projectId, id.platform, id.userId);
3572
3581
  }
3573
3582
  /** Re-apply memoized hydrated texts onto freshly-mapped messages. Both
3574
3583
  * clients call this right after their mapper runs (loadHistory does it
@@ -4118,7 +4127,7 @@ var ChatSession = class {
4118
4127
  }
4119
4128
  if (stageId) delete this._liveStages[stageId];
4120
4129
  var llmComposed = composedForLlm || composed;
4121
- var key = !id.projectId ? "" : id.projectId + "#" + id.platform;
4130
+ var key = chatCacheKey(id.projectId, id.platform, id.userId);
4122
4131
  var offChat = !!key && key !== this.getHistoryCacheKey();
4123
4132
  var isQueuedSend = !offChat && (useBgQueue || this.state.sending || this.state.messages.some(function(m) {
4124
4133
  return (m.isPending || m.isPendingQueued) && !m.isBackgroundTask && !m._useBgQueue;
@@ -4684,7 +4693,8 @@ var ChatSession = class {
4684
4693
  cancelIndexingGroup(group) {
4685
4694
  var self = this;
4686
4695
  if (!group || !group.key) return;
4687
- var scoped = this.getHistoryCacheKey() + "|" + group.key;
4696
+ var idn = this.host.getIdentity();
4697
+ var scoped = indexScopeKey(idn.projectId, idn.platform) + "|" + group.key;
4688
4698
  this.cancelledIndexKeys.add(scoped);
4689
4699
  if (!group.finished) {
4690
4700
  var stoppedIds = {};
@@ -5152,7 +5162,7 @@ var ChatSession = class {
5152
5162
  if (!entry) return "";
5153
5163
  var file = entry.storagePath || entry.filename;
5154
5164
  if (!file) return "";
5155
- return entry.projectId + "#" + entry.platform + "|" + file;
5165
+ return indexScopeKey(entry.projectId, entry.platform) + "|" + file;
5156
5166
  }
5157
5167
  /**
5158
5168
  * Reconcile the bg queue with the files the user has stopped.
@@ -5679,7 +5689,7 @@ var ChatSession = class {
5679
5689
  loadHistory(fetchMore, token) {
5680
5690
  var self = this;
5681
5691
  var id = this.host.getIdentity();
5682
- var loadKey = !id.projectId || id.platform === "none" ? "" : id.projectId + "#" + id.platform;
5692
+ var loadKey = chatCacheKey(id.projectId, id.platform, id.userId);
5683
5693
  if (token === void 0) token = this.state.gateRefreshToken;
5684
5694
  if (this.state.loadingHistory && this.state.historyRequestToken === token || id.platform === "none" || !id.projectId) {
5685
5695
  return Promise.resolve();
@@ -5698,7 +5708,17 @@ var ChatSession = class {
5698
5708
  if (fetchMore && this.state.historyStartKeyHistory.length) options.startKeyHistory = this.state.historyStartKeyHistory.slice();
5699
5709
  if (!fetchMore) options.deferBg = true;
5700
5710
  var fetchHistory = function() {
5701
- return getSplitChatHistory({ service: projectId, owner, platform, userId: id.userId }, options);
5711
+ return getSplitChatHistory({
5712
+ service: projectId,
5713
+ owner,
5714
+ platform,
5715
+ userId: id.userId,
5716
+ // An anonymous visitor's history is scoped server side by
5717
+ // ip + "(" + user_agent + ")", which two devices behind one NAT
5718
+ // share. Read this device's own queue instead. See
5719
+ // scopeSurfaceToQueue.
5720
+ scopeSurfaceToQueue: !!id.anonymous
5721
+ }, options);
5702
5722
  };
5703
5723
  return Promise.resolve().then(fetchHistory).catch(function(err) {
5704
5724
  if (isAuthExpiredError(err) && !isNonRetryableRequestError(err)) return self.host.refreshSession().then(fetchHistory);
@@ -5720,6 +5740,10 @@ var ChatSession = class {
5720
5740
  var mapped = mapHistoryListToMessages(list, platform, {
5721
5741
  clearedAt: self.host.getClearedAt(),
5722
5742
  projectId: id.projectId,
5743
+ // So the `_ownerKey` stamped on server history matches loadKey and
5744
+ // the cache key. Without it every mapped bubble carries a
5745
+ // two-segment stamp that no comparison can ever match.
5746
+ userId: id.userId,
5723
5747
  formatIndexingLabel: self.host.formatIndexingLabel
5724
5748
  }).messages;
5725
5749
  self.applyHydratedBodies(mapped);
@@ -5928,6 +5952,7 @@ var ChatSession = class {
5928
5952
  var m2 = mapHistoryListToMessages(sorted, platform, {
5929
5953
  clearedAt: self.host.getClearedAt(),
5930
5954
  projectId: id.projectId,
5955
+ userId: id.userId,
5931
5956
  formatIndexingLabel: self.host.formatIndexingLabel
5932
5957
  }).messages;
5933
5958
  self.applyHydratedBodies(m2);
@@ -6787,6 +6812,7 @@ exports.callClaudeWithMcp = callClaudeWithMcp;
6787
6812
  exports.callClaudeWithPublicMcp = callClaudeWithPublicMcp;
6788
6813
  exports.callOpenAIWithPublicMcp = callOpenAIWithPublicMcp;
6789
6814
  exports.canonicalizePathForm = canonicalizePathForm;
6815
+ exports.chatCacheKey = chatCacheKey;
6790
6816
  exports.chatEngineConfig = chatEngineConfig;
6791
6817
  exports.classifyInlineLink = classifyInlineLink;
6792
6818
  exports.clearAttachmentParsers = clearAttachmentParsers;
@@ -6830,6 +6856,7 @@ exports.groupAttachmentFailures = groupAttachmentFailures;
6830
6856
  exports.hasBom = hasBom;
6831
6857
  exports.hydrateImagePreviews = hydrateImagePreviews;
6832
6858
  exports.indexDoneUniqueId = indexDoneUniqueId;
6859
+ exports.indexScopeKey = indexScopeKey;
6833
6860
  exports.indexingAccessGroup = indexingAccessGroup;
6834
6861
  exports.isAuthExpiredError = isAuthExpiredError;
6835
6862
  exports.isBgIndexingQueue = isBgIndexingQueue;