@tokenoftrust/storefront-runner 4.7.9 → 4.7.10

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.
@@ -35,6 +35,9 @@
35
35
  * carries only the reason, the cause, elapsed ms, whether the action was held,
36
36
  * whether `FC.client` existed, Foxy's own full-page and bypass decisions, the
37
37
  * document ready state and viewport/screen/body widths — never a URL or session.
38
+ * A CSP refusal raised by the drawer's own scripts is the cause when nothing else
39
+ * failed (`csp-eval`, `csp-inline`, `csp-resource`): the page policy admits no
40
+ * eval, so a store template that carries an inline script breaks the drawer.
38
41
  *
39
42
  * Every cart open waits for this store's Foxy session. The id comes from the
40
43
  * same-origin session endpoint (an HttpOnly cookie the browser cannot read) and
@@ -271,6 +274,20 @@ export function lazyCheckoutLoaderJs(options: LazyCheckoutLoaderOptions): string
271
274
  failure = cause;
272
275
  runHeld();
273
276
  }
277
+ // A drawer can report ready and still fail to render: the page CSP has no
278
+ // 'unsafe-eval', so a store template carrying an inline <script> (which the
279
+ // drawer's jQuery runs through eval) throws inside cart.render. A refusal raised
280
+ // by the drawer's own scripts is kept as the cause of a later fall-through.
281
+ var drawerOrigins = [cartOrigin];
282
+ try { drawerOrigins.push(new URL(src, document.baseURI).origin); } catch (e) {}
283
+ var cspRefusal = null;
284
+ document.addEventListener('securitypolicyviolation', function (event) {
285
+ var from = null;
286
+ try { from = new URL(event.sourceFile).origin; } catch (e) {}
287
+ if (!from || drawerOrigins.indexOf(from) === -1) return;
288
+ var blocked = event.blockedURI;
289
+ cspRefusal = 'csp-' + (blocked === 'eval' || blocked === 'inline' ? blocked : 'resource');
290
+ });
274
291
  // A cart action reaching the window unhandled after the drawer settled navigates
275
292
  // to the full cart page. Record why, with no URL or session in the record.
276
293
  function fallthrough(kind, el) {
@@ -284,9 +301,10 @@ export function lazyCheckoutLoaderJs(options: LazyCheckoutLoaderOptions): string
284
301
  return !!(node && node.classList && (node.classList.contains('fc-sidecart--bypass') || node.hasAttribute('data-fc-sidecart-bypass')));
285
302
  }
286
303
  var reason = state === 'ready' ? 'drawer-declined' : 'drawer-unavailable';
304
+ var cause = failure || cspRefusal;
287
305
  var detail = {
288
306
  reason: reason,
289
- cause: failure,
307
+ cause: cause,
290
308
  kind: kind,
291
309
  held: replaying === el,
292
310
  elapsedMs: armedAt ? Date.now() - armedAt : null,
@@ -298,7 +316,7 @@ export function lazyCheckoutLoaderJs(options: LazyCheckoutLoaderOptions): string
298
316
  screenWidth: window.screen ? window.screen.availWidth : null,
299
317
  bodyWidth: body ? body.clientWidth : null
300
318
  };
301
- document.documentElement.setAttribute('data-cart-fallthrough', reason + (failure ? ':' + failure : ''));
319
+ document.documentElement.setAttribute('data-cart-fallthrough', reason + (cause ? ':' + cause : ''));
302
320
  try { console.warn('[tot-cart] cart fell through to the cart page', detail); } catch (e) {}
303
321
  try { window.dispatchEvent(new window.CustomEvent('tot:cart-fallthrough', { detail: detail })); } catch (e) {}
304
322
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "4.7.9",
3
+ "version": "4.7.10",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
6
6
  "packageManager": "pnpm@11.9.0",