bunnyquery 1.8.8 → 1.8.9

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
@@ -566,8 +566,41 @@ Index the REMAINING windows - one record per row/item, looking at any page image
566
566
  var EXPIRED_ATTACHMENT_URL_ORIGIN = "https://" + EXPIRED_ATTACHMENT_URL_HOST;
567
567
  var LINK_LABEL_MAX_DISPLAY_CHARS = 32;
568
568
  var EXPIRED_LINK_REFRESH_EXPIRES_SECONDS = 20 * 60;
569
+ var PREVIEW_URL_EXPIRES_SECONDS = 60 * 60;
569
570
  var PREVIEW_BROWSER_CACHE_SECONDS = 7 * 24 * 60 * 60;
570
571
  var LINK_REFRESH_WINDOW_MS = (EXPIRED_LINK_REFRESH_EXPIRES_SECONDS - 5 * 60) * 1e3;
572
+ var MINT_CACHE_GENERATION = 2;
573
+ function mintCacheBustStamp(now) {
574
+ return Math.floor((Date.now() ) / LINK_REFRESH_WINDOW_MS);
575
+ }
576
+ function previewMintCacheToken(refresh) {
577
+ if (!refresh) return String(MINT_CACHE_GENERATION);
578
+ return MINT_CACHE_GENERATION + "." + mintCacheBustStamp();
579
+ }
580
+ var PRESIGN_SAFETY_MARGIN_MS = 60 * 1e3;
581
+ function presignExpiryEpochMs(url) {
582
+ if (!url) return null;
583
+ var q = url.indexOf("?");
584
+ if (q < 0) return null;
585
+ var params;
586
+ try {
587
+ params = new URLSearchParams(url.slice(q + 1));
588
+ } catch (e) {
589
+ return null;
590
+ }
591
+ var v2 = params.get("Expires");
592
+ if (v2 && /^\d+$/.test(v2)) return parseInt(v2, 10) * 1e3;
593
+ var signed = params.get("X-Amz-Date");
594
+ var lifetime = params.get("X-Amz-Expires");
595
+ if (signed && lifetime && /^\d+$/.test(lifetime)) {
596
+ var m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(signed);
597
+ if (m) {
598
+ var at = Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]);
599
+ return at + parseInt(lifetime, 10) * 1e3;
600
+ }
601
+ }
602
+ return null;
603
+ }
571
604
  function createInlineLinkRegex() {
572
605
  return /src::(\S+)|\[([^\]\n]+)\]\((https?:\/\/(?:[^\s()]|\([^\s()]*\))+)\)|\[([^\]\n]+)\]\(((?:[^()\n]|\([^()\n]*\))+)\)|(https?:\/\/[^\s<>"']+)/g;
573
606
  }
@@ -812,6 +845,13 @@ Index the REMAINING windows - one record per row/item, looking at any page image
812
845
  function linkUnavailableKeyForHref(href) {
813
846
  return "href:" + (href || "");
814
847
  }
848
+ function linkUnavailableKeysForPath(remotePath) {
849
+ if (!remotePath) return [];
850
+ return [
851
+ linkUnavailableKeyForPath(remotePath),
852
+ linkUnavailableKeyForHref(buildDisplayExpiredAttachmentHref(remotePath))
853
+ ];
854
+ }
815
855
  function isLinkUnavailable(link, map) {
816
856
  if (!link || !map) return false;
817
857
  if (link.remotePath && map[linkUnavailableKeyForPath(link.remotePath)]) return true;
@@ -1206,8 +1246,11 @@ Index the REMAINING windows - one record per row/item, looking at any page image
1206
1246
  }
1207
1247
  function peekImagePreviewUrl(ctx, remotePath) {
1208
1248
  var hit = previewUrlCache[cacheKey(ctx.scope, remotePath)];
1209
- if (hit && Date.now() - hit.at < LINK_REFRESH_WINDOW_MS) return hit.url;
1210
- return null;
1249
+ if (!hit) return null;
1250
+ if (Date.now() - hit.at >= LINK_REFRESH_WINDOW_MS) return null;
1251
+ var dies = presignExpiryEpochMs(hit.url);
1252
+ if (dies !== null && Date.now() >= dies - PRESIGN_SAFETY_MARGIN_MS) return null;
1253
+ return hit.url;
1211
1254
  }
1212
1255
  function resolveImagePreviewUrl(ctx, remotePath, contentType, refresh) {
1213
1256
  var key = cacheKey(ctx.scope, remotePath);
@@ -1257,6 +1300,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
1257
1300
  img.setAttribute("data-bq-img-state", "loading");
1258
1301
  img.addEventListener("load", function() {
1259
1302
  img.setAttribute("data-bq-img-state", "ready");
1303
+ img.removeAttribute("data-bq-img-retry");
1260
1304
  if (ctx.onLoad) ctx.onLoad(path);
1261
1305
  });
1262
1306
  img.addEventListener("error", function() {
@@ -8217,7 +8261,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
8217
8261
  if (cdn === false && opts.browserCache) {
8218
8262
  reqOpts.method = "get";
8219
8263
  reqOpts.stableGateway = true;
8220
- if (opts.refresh) reqOpts.revalidate = true;
8264
+ body.nocache = previewMintCacheToken(opts.refresh);
8221
8265
  body.browser_cache = opts.browserCache;
8222
8266
  var uid = S.user && S.user.user_id;
8223
8267
  if (uid) body.uid = uid;
@@ -8736,10 +8780,7 @@ Index the REMAINING windows - one record per row/item, looking at any page image
8736
8780
  return getTemporaryUrlDb(remotePath, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, false);
8737
8781
  }
8738
8782
  var unavailableRepaintQueued = false;
8739
- function markLinkUnavailable(key) {
8740
- if (!key || unavailableLinkMap[key]) return;
8741
- unavailableLinkMap[key] = true;
8742
- if (!refreshedLinkExpiryTimer) scheduleNextLinkExpiryBoundary();
8783
+ function queueUnavailableRepaint() {
8743
8784
  if (unavailableRepaintQueued) return;
8744
8785
  unavailableRepaintQueued = true;
8745
8786
  setTimeout(function() {
@@ -8747,18 +8788,37 @@ Index the REMAINING windows - one record per row/item, looking at any page image
8747
8788
  renderMessages();
8748
8789
  }, 0);
8749
8790
  }
8791
+ function markLinkUnavailable(key) {
8792
+ if (!key || unavailableLinkMap[key]) return;
8793
+ unavailableLinkMap[key] = true;
8794
+ if (!refreshedLinkExpiryTimer) scheduleNextLinkExpiryBoundary();
8795
+ queueUnavailableRepaint();
8796
+ }
8797
+ function clearLinkUnavailable(keys) {
8798
+ var changed = false;
8799
+ for (var i = 0; i < (keys || []).length; i++) {
8800
+ var k = keys[i];
8801
+ if (!k || !unavailableLinkMap[k]) continue;
8802
+ delete unavailableLinkMap[k];
8803
+ changed = true;
8804
+ }
8805
+ if (changed) queueUnavailableRepaint();
8806
+ }
8750
8807
  function imagePreviewCtx() {
8751
8808
  return {
8752
8809
  scope: S.projectId || "default",
8753
8810
  mint: function(remotePath, contentType, refresh) {
8754
- return getTemporaryUrlDb(remotePath, EXPIRED_LINK_REFRESH_EXPIRES_SECONDS, false, contentType, {
8811
+ return getTemporaryUrlDb(remotePath, PREVIEW_URL_EXPIRES_SECONDS, false, contentType, {
8755
8812
  browserCache: PREVIEW_BROWSER_CACHE_SECONDS,
8756
8813
  refresh
8757
8814
  });
8758
8815
  },
8759
8816
  // An image arriving late pushes the conversation down under the
8760
- // viewport. Re-pin only if the user was already at the bottom.
8761
- onLoad: function() {
8817
+ // viewport. Re-pin only if the user was already at the bottom. A
8818
+ // paint is also proof the file is reachable, so it lifts any mark an
8819
+ // earlier failure left on this file's chips.
8820
+ onLoad: function(path) {
8821
+ clearLinkUnavailable(linkUnavailableKeysForPath(path));
8762
8822
  scrollToBottomIfSticky(false);
8763
8823
  },
8764
8824
  // The mint was refused, or the url it minted would not load. Either
package/dist/engine.cjs CHANGED
@@ -603,8 +603,41 @@ var EXPIRED_ATTACHMENT_URL_HOST = "_expired_.url";
603
603
  var EXPIRED_ATTACHMENT_URL_ORIGIN = "https://" + EXPIRED_ATTACHMENT_URL_HOST;
604
604
  var LINK_LABEL_MAX_DISPLAY_CHARS = 32;
605
605
  var EXPIRED_LINK_REFRESH_EXPIRES_SECONDS = 20 * 60;
606
+ var PREVIEW_URL_EXPIRES_SECONDS = 60 * 60;
606
607
  var PREVIEW_BROWSER_CACHE_SECONDS = 7 * 24 * 60 * 60;
607
608
  var LINK_REFRESH_WINDOW_MS = (EXPIRED_LINK_REFRESH_EXPIRES_SECONDS - 5 * 60) * 1e3;
609
+ var MINT_CACHE_GENERATION = 2;
610
+ function mintCacheBustStamp(now) {
611
+ return Math.floor((now == null ? Date.now() : now) / LINK_REFRESH_WINDOW_MS);
612
+ }
613
+ function previewMintCacheToken(refresh) {
614
+ if (!refresh) return String(MINT_CACHE_GENERATION);
615
+ return MINT_CACHE_GENERATION + "." + mintCacheBustStamp();
616
+ }
617
+ var PRESIGN_SAFETY_MARGIN_MS = 60 * 1e3;
618
+ function presignExpiryEpochMs(url) {
619
+ if (!url) return null;
620
+ var q = url.indexOf("?");
621
+ if (q < 0) return null;
622
+ var params;
623
+ try {
624
+ params = new URLSearchParams(url.slice(q + 1));
625
+ } catch (e) {
626
+ return null;
627
+ }
628
+ var v2 = params.get("Expires");
629
+ if (v2 && /^\d+$/.test(v2)) return parseInt(v2, 10) * 1e3;
630
+ var signed = params.get("X-Amz-Date");
631
+ var lifetime = params.get("X-Amz-Expires");
632
+ if (signed && lifetime && /^\d+$/.test(lifetime)) {
633
+ var m = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(signed);
634
+ if (m) {
635
+ var at = Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]);
636
+ return at + parseInt(lifetime, 10) * 1e3;
637
+ }
638
+ }
639
+ return null;
640
+ }
608
641
  function createInlineLinkRegex() {
609
642
  return /src::(\S+)|\[([^\]\n]+)\]\((https?:\/\/(?:[^\s()]|\([^\s()]*\))+)\)|\[([^\]\n]+)\]\(((?:[^()\n]|\([^()\n]*\))+)\)|(https?:\/\/[^\s<>"']+)/g;
610
643
  }
@@ -855,6 +888,13 @@ function linkUnavailableKeyForPath(remotePath) {
855
888
  function linkUnavailableKeyForHref(href) {
856
889
  return "href:" + (href || "");
857
890
  }
891
+ function linkUnavailableKeysForPath(remotePath) {
892
+ if (!remotePath) return [];
893
+ return [
894
+ linkUnavailableKeyForPath(remotePath),
895
+ linkUnavailableKeyForHref(buildDisplayExpiredAttachmentHref(remotePath))
896
+ ];
897
+ }
858
898
  function isLinkUnavailable(link, map) {
859
899
  if (!link || !map) return false;
860
900
  if (link.remotePath && map[linkUnavailableKeyForPath(link.remotePath)]) return true;
@@ -1277,8 +1317,11 @@ function clearImagePreviewCache(scope) {
1277
1317
  }
1278
1318
  function peekImagePreviewUrl(ctx, remotePath) {
1279
1319
  var hit = previewUrlCache[cacheKey(ctx.scope, remotePath)];
1280
- if (hit && Date.now() - hit.at < LINK_REFRESH_WINDOW_MS) return hit.url;
1281
- return null;
1320
+ if (!hit) return null;
1321
+ if (Date.now() - hit.at >= LINK_REFRESH_WINDOW_MS) return null;
1322
+ var dies = presignExpiryEpochMs(hit.url);
1323
+ if (dies !== null && Date.now() >= dies - PRESIGN_SAFETY_MARGIN_MS) return null;
1324
+ return hit.url;
1282
1325
  }
1283
1326
  function resolveImagePreviewUrl(ctx, remotePath, contentType, refresh) {
1284
1327
  var key = cacheKey(ctx.scope, remotePath);
@@ -1328,6 +1371,7 @@ function hydrateOne(img, ctx) {
1328
1371
  img.setAttribute("data-bq-img-state", "loading");
1329
1372
  img.addEventListener("load", function() {
1330
1373
  img.setAttribute("data-bq-img-state", "ready");
1374
+ img.removeAttribute("data-bq-img-retry");
1331
1375
  if (ctx.onLoad) ctx.onLoad(path);
1332
1376
  });
1333
1377
  img.addEventListener("error", function() {
@@ -6109,12 +6153,15 @@ exports.MAX_OUTPUT_BY_MODEL = MAX_OUTPUT_BY_MODEL;
6109
6153
  exports.MAX_OUTPUT_TOKENS = MAX_OUTPUT_TOKENS;
6110
6154
  exports.MAX_PARSED_CONTENT_CHARS = MAX_PARSED_CONTENT_CHARS;
6111
6155
  exports.MCP_NAME = MCP_NAME;
6156
+ exports.MINT_CACHE_GENERATION = MINT_CACHE_GENERATION;
6112
6157
  exports.MIN_INPUT_TOKEN_BUDGET = MIN_INPUT_TOKEN_BUDGET;
6113
6158
  exports.MIN_PER_REQUEST_INPUT_CAP = MIN_PER_REQUEST_INPUT_CAP;
6114
6159
  exports.OUTPUT_TOKEN_RESERVE = OUTPUT_TOKEN_RESERVE;
6115
6160
  exports.POLL_INTERVAL = POLL_INTERVAL;
6161
+ exports.PRESIGN_SAFETY_MARGIN_MS = PRESIGN_SAFETY_MARGIN_MS;
6116
6162
  exports.PREVIEWABLE_IMAGE_CONTENT_TYPES = PREVIEWABLE_IMAGE_CONTENT_TYPES;
6117
6163
  exports.PREVIEW_BROWSER_CACHE_SECONDS = PREVIEW_BROWSER_CACHE_SECONDS;
6164
+ exports.PREVIEW_URL_EXPIRES_SECONDS = PREVIEW_URL_EXPIRES_SECONDS;
6118
6165
  exports.RENDER_FROM_TOKEN = RENDER_FROM_TOKEN;
6119
6166
  exports.RTF_EXTS = RTF_EXTS;
6120
6167
  exports.RUN_RECORD_WORKING_STALE_MS = RUN_RECORD_WORKING_STALE_MS;
@@ -6194,12 +6241,14 @@ exports.isServerExtractable = isServerExtractable;
6194
6241
  exports.isServiceDbAttachmentHref = isServiceDbAttachmentHref;
6195
6242
  exports.linkUnavailableKeyForHref = linkUnavailableKeyForHref;
6196
6243
  exports.linkUnavailableKeyForPath = linkUnavailableKeyForPath;
6244
+ exports.linkUnavailableKeysForPath = linkUnavailableKeysForPath;
6197
6245
  exports.listClaudeModels = listClaudeModels;
6198
6246
  exports.listOpenAIModels = listOpenAIModels;
6199
6247
  exports.looksLikeRtf = looksLikeRtf;
6200
6248
  exports.makeExtractPlaceholder = makeExtractPlaceholder;
6201
6249
  exports.mapHistoryListToMessages = mapHistoryListToMessages;
6202
6250
  exports.markImagePreviewStale = markImagePreviewStale;
6251
+ exports.mintCacheBustStamp = mintCacheBustStamp;
6203
6252
  exports.needsBomForExt = needsBomForExt;
6204
6253
  exports.normalizeAttachmentPathCandidate = normalizeAttachmentPathCandidate;
6205
6254
  exports.normalizeExt = normalizeExt;
@@ -6212,7 +6261,9 @@ exports.parseIndexingLabel = parseIndexingLabel;
6212
6261
  exports.parseIndexingRequestText = parseIndexingRequestText;
6213
6262
  exports.peekImagePreviewUrl = peekImagePreviewUrl;
6214
6263
  exports.prepareDownloadText = prepareDownloadText;
6264
+ exports.presignExpiryEpochMs = presignExpiryEpochMs;
6215
6265
  exports.previewImageContentType = previewImageContentType;
6266
+ exports.previewMintCacheToken = previewMintCacheToken;
6216
6267
  exports.previewableExtOf = previewableExtOf;
6217
6268
  exports.readExpiredAttachmentHref = readExpiredAttachmentHref;
6218
6269
  exports.registerAttachmentParser = registerAttachmentParser;