riant_preorder_limits_for_market_382140642";window._RestockRocketConfig.cachedVariantShippingTexts = {"variant_shipping_texts":{},"updated_at":"2026-07-28T22:08:31Z","shopify_market_id":382140642,"market_locations_enabled":false};
window._RestockRocketConfig.cachedVariantShippingTextsMarketKey = "variant_shipping_texts_for_market_382140642";window._RestockRocketConfig.sellingPlans = [{"shopify_selling_plan_group_id":98590196095,"shopify_selling_plan_id":713071886719,"enabled":true,"variant_ids":[55569712382335,55569712415103,55569712480639,55570017616255,55570017550719,55569712447871,55570017583487],"product_variants_source":"custom","name":"Preorder","preorder_button_text":"Preorder","preorder_button_description":"Note: This is a preorder. Items will ship based on the estimated delivery date.","preorder_button_description_enabled":true,"preorder_button_description_background_color":"#ebebeb","preorder_button_description_text_color":"#000000","preorder_button_description_border_radius":10,"preorder_button
_description_show_quantity_limit":false,"preorder_button_description_quantity_limit_suffix":" units available for preorder","preorder_button_description_shipping_text_prefix":"Shipping: ","delivery_exact_time":null,"delivery_after_n_intervals":null,"delivery_at":"2025-07-26T09:20:18.169Z","delivery_type":"asap","quantity_limit_text":"{{ quantity }} units available for preorder","preorder_button_description_show_shipping":true,"preorder_button_description_icons_enabled":true,"preorder_shipping_text":"Shipping: {{ date }}","shipping_applies_to_all_products":true,"shipping_text":"Estimated to ship within 2 months","payment_type":"full","billing_checkout_charge_type":"percentage","billing_checkout_charge_amount":null,"billing_checkout_charge_percentage":"100.0","pricing_type":"no_discount","pricing_amount":null,"pricing_percentage":null,"discount_text":"Save {{ discount }}","billing_title":"Full payment","billing_description":null,"enable_billing_widget":false,"inventory_provider":"stoq","preorder_badge_enabled":
false,"preorder_badge_text":"Preorder","preorder_badge_text_color":"#FFFFFF","preorder_badge_background_color":"#000000","preorder_discounted_price_enabled":null,"payment_line_item_property_enabled":false,"shipping_line_item_property_enabled":true,"custom_line_item_property_text":null,"preorder_button_text_color":"#ffffff","preorder_button_background_color":"#565557","preorder_button_colors_enabled":true,"markets_enabled":false,"market_id":13779632354,"shopify_market_ids":[],"use_shopify_selling_plan":true,"use_simplified_shipping_text":false,"translations":{},"payment_options":[{"billing_type":"no_remaining_balance","billing_checkout_charge_type":"percentage","billing_checkout_charge_amount":null,"billing_checkout_charge_percentage":"100.0","billing_at":"2025-07-26T09:20:38.472Z","billing_after_n_intervals":7,"billing_after_interval_type":"day","pricing_type":"no_discount","pricing_amount":null,"pricing_percentage":null,"billing_title":"Full payment","billing_description":null,"discount_text":"Save {{ discou
nt }}","shopify_selling_plan_id":713071886719,"is_default":true,"type":"full","translations":{}}],"require_preorder_acknowledgement":false,"preorder_acknowledgement_text":"I acknowledge and agree to the preorder terms and conditions for this product.","disable_button_until_acknowledged":false,"preorder_min_quantity":null,"preorder_max_quantity":null,"countdown_timer_enabled":false,"countdown_timer_style":"text","countdown_timer_text_color":"#000000","countdown_timer_background_color":"#f5f5f5","countdown_timer_border_radius":8,"countdown_timer_format":"DHMS","countdown_timer_use_schedule_dates":true,"countdown_timer_custom_start_date":null,"countdown_timer_custom_end_date":null,"countdown_timer_starts_text":null,"countdown_timer_ends_text":null,"schedule_offer":false,"schedule_start_date":null,"schedule_end_date":null,"updated_at":"2025-08-19T10:05:43.042Z","allow_mixed_cart":true,"mixed_cart_error_message":"Preorders must be purchased separately from regular items. Please complete your current order first, or clear your cart to continue.","b2b_enabled":true,"preorder_progress_bar_enabled":false,"preorder_progress_bar_text":"{{ sold }} of {{ total }} claimed","preorder_progress_bar_fill_color":"#000000","preorder_progress_bar_background_color":"#e5e5e5","preorder_progress_bar_text_color":"#FFFFFF","preorder_progress_bar_border_radius":4,"preorder_progress_bar_show_percentage":false}];(function() {
const cachedData = {"plans":[{"shopify_selling_plan_group_id":98590196095,"shopify_selling_plan_id":713071886719,"enabled":true,"variant_ids":[55569712382335,55569712415103,55569712480639,55570017616255,55570017550719,55569712447871,55570017583487],"product_variants_source":"custom","name":"Preorder","preorder_button_text":"Preorder","preorder_button_description":"Note: This is a preorder. Items will ship based on the estimated delivery date.","preorder_button_description_enabled":true,"preorder_button_description_background_color":"#ebebeb","preorder_button_description_text_color":"#000000","preorder_button_descr
iption_border_radius":10,"preorder_button_description_show_quantity_limit":false,"preorder_button_description_quantity_limit_suffix":" units available for preorder","preorder_button_description_shipping_text_prefix":"Shipping: ","delivery_exact_time":null,"delivery_after_n_intervals":null,"delivery_at":"2025-07-26T09:20:18.169Z","delivery_type":"asap","quantity_limit_text":"{{ quantity }} units available for preorder","preorder_button_description_show_shipping":true,"preorder_button_description_icons_enabled":true,"preorder_shipping_text":"Shipping: {{ date }}","shipping_applies_to_all_products":true,"shipping_text":"Estimated to ship within 2 months","payment_type":"full","billing_checkout_charge_type":"percentage","billing_checkout_charge_amount":null,"billing_checkout_charge_percentage":"100.0","pricing_type":"no_discount","pricing_amount":null,"pricing_percentage":null,"discount_text":"Save {{ discount }}","billing_title":"Full payment","billing_description":null,"enable_billing_widget":false,"inventory_provider":"stoq","preorder_badge_enabled":false,"preorder_badge_text":"Preorder","preorder_badge_text_color":"#FFFFFF","preorder_badge_background_color":"#000000","preorder_discounted_price_enabled":null,"payment_line_item_property_enabled":false,"shipping_line_item_property_enabled":true,"custom_line_item_property_text":null,"preorder_button_text_color":"#ffffff","preorder_button_background_color":"#565557","preorder_button_colors_enabled":true,"markets_enabled":false,"market_id":13779632354,"shopify_market_ids":[],"use_shopify_selling_plan":true,"use_simplified_shipping_text":false,"translations":{},"payment_options":[{"billing_type":"no_remaining_balance","billing_checkout_charge_type":"percentage","billing_checkout_charge_amount":null,"billing_checkout_charge_percentage":"100.0","billing_at":"2025-07-26T09:20:38.472Z","billing_after_n_intervals":7,"billing_after_interval_type":"day","pricing_type":"no_discount","pricing_amount":null,"pricing_percentage":null,"billing_title":"Full payment","billing_descriptSizeion":null,"discount_text":"Save {{ discount }}","shopify_selling_plan_id":713071886719,"is_default":true,"type":"full","translations":{}}],"require_preorder_acknowledgement":false,"preorder_acknowledgement_text":"I acknowledge and agree to the preorder terms and conditions for this product.","disable_button_until_acknowledged":false,"preorder_min_quantity":null,"preorder_max_quantity":null,"countdown_timer_enabled":false,"countdown_timer_style":"text","countdown_timer_text_color":"#000000","countdown_timer_background_color":"#f5f5f5","countdown_timer_border_radius":8,"countdown_timer_format":"DHMS","countdown_timer_use_schedule_dates":true,"countdown_timer_custom_start_date":null,"countdown_timer_custom_end_date":null,"countdown_timer_starts_text":null,"countdown_timer_ends_text":null,"schedule_offer":false,"schedule_start_date":null,"schedule_end_date":null,"updated_at":"2025-08-19T10:05:43.042Z","allow_mixed_cart":true,"mixed_cart_error_message":"Preorders must be purchased separately from regular items. Pl ease complete your current order first, or clear your cart to continue.","b2b_enabled":true,"preorder_progress_bar_enabled":false,"preorder_progress_bar_text":"{{ sold }} of {{ total }} claimed","preorder_progress_bar_fill_color":"#000000","preorder_progress_bar_background_color":"#e5e5e5","preorder_progress_bar_text_color":"#FFFFFF","preorder_progress_bar_border_radius":4,"preorder_progress_bar_show_percentage":false}],"disabled_plan_ids":[713813721471,713176482175,714631872895],"cached_at":"2026-04-09T09:16:46Z"};
if (cachedData && typeof cachedData === 'object' && cachedData.cached_at) {
// Find the maximum updated_at from all items in old array
const oldPlans = window._RestockRocketConfig.sellingPlans;
const maxUpdatedAt = Array.isArray(oldPlans) && oldPlans.length > 0
? oldPlans.reduce(function(max, plan) {
// Parse dates for proper comparison (handles mixed ISO formats)
if (plan.updated_at) {
const planDate = new Date(p
lan.updated_at);
const maxDate = max ? new Date(max) : null;
return (!maxDate || (planDate && !isNaN(planDate) && planDate > maxDate)) ? plan.updated_at : max;
}
return max;
}, '')
: null;
// Use cached if old array is empty/has no timestamps, or cached is newer
// Parse dates for comparison to handle format differences (+00:00 vs .000Z)
const cachedDate = new Date(cachedData.cached_at);
const maxDate = maxUpdatedAt ? new Date(maxUpdatedAt) : null;
const useCached = !maxUpdatedAt || (cachedDate && !isNaN(cachedDate) && (!maxDate || cachedDate > maxDate));
if (useCached) {
if (Array.isArray(cachedData.plans)) {
window._RestockRocketConfig.sellingPlans = cachedData.plans;
// Only use disabled_plan_ids when using cached plans
window._RestockRocketConfig.disabledSellingPlanIds = cachedData.disabled_plan_ids || [];
console.debug('[RR] Using selling plans from cachedSellingPlans (cached_at: ' + cachedData.cached_at + ')');
}
} else {
// When using old format (stale cache), don't trust disabled_plan_ids
window._RestockRocketConfig.disabledSellingPlanIds = [];
console.debug('[RR] Using selling plans from old format (max updated_at: ' + maxUpdatedAt + ')');
}
}
})();window._RestockRocketConfig.enabledNotifyMeVariantIds = [];window._RestockRocketConfig.disabledNotifyMeVariantIds = [];window._RestockRocketConfig.backInStockTemplates = [];window._RestockRocketConfig.restockNotes = {};window._RestockRocketConfig.integrations = [{"id":"15c94526-b6b8-4de1-9bc1-23b1ca52ddb0","shop_id":38436,"enabled":true,"page_types":["product","collection","index","search","page","cart","list-collections","article","blog"],"configuration":{"toastDuration":10000,"toastPosition":"bottom-right","enableXHRHijack":true,"enableFetchHijack":true,"quantityLimitDisabled":false},"type":"hijack","css_co
nfig":null,"js_config":null,"created_at":"2025-07-26T09:16:04.076Z","updated_at":"2025-07-26T09:16:04.076Z"}];window._RestockRocketConfig.obfuscateInventoryQuantity = false;window._RestockRocketConfig.product = {"id":15776142033279,"title":"Argon 18 Dark Matter SRAM Force XPLR AXS","handle":"argon-18-dark-matter-sram-force-xplr-axs","description":"\u003ch2\u003eArgon 18 Dark Matter SRAM Force XPLR AXS\u003c\/h2\u003e\u003cp\u003eThe Dark Matter is a performance gravel platform designed for rugged racing and rough adventure, with modern tyre clearance, stable geometry and practical details for longer mixed-terrain rides.\u003c\/p\u003e\u003cp\u003eThis version is supplied in the SRAM Force XPLR AXS configuration and is available in Root Beer.\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003ePerformance gravel carbon platform\u003c\/li\u003e\n\u003cli\u003eIntegrated cable routing\u003c\/li\u003e\n\u003cli\u003eStorage Optimization System\u003c\/li\u003e\n\u003cli\u003eWide gravel tyre clearance\u003c\/li\u003e\n\u003cli\u003eBuilt for gravel racing and rough adventure riding\u003c\/li\u003e\n\u003cli\u003eAvailable sizes: XXS 44-46, XS 47-50, S 51-53, M 54-56, L 57-59 and XL 60-62\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eKey specification\u003c\/h3\u003e\u003ctable\u003e\u003ctbody\u003e\n\u003ctr\u003e\n\u003cth\u003eFrame\u003c\/th\u003e\n\u003ctd\u003eDark Matter\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eFork\u003c\/th\u003e\n\u003ctd\u003eDark Matter\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eGroupset\u003c\/th\u003e\n\u003ctd\u003eSRAM Force XPLR AXS E1\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eWheelset\u003c\/th\u003e\n\u003ctd\u003eZIPP 303 XPLR S\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eTyres \/ Clearance\u003c\/th\u003e\n\u003ctd\u003eSchwalbe G-One RX PRO TLR 700x50c\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eColours\u003c\/th\u003e\n\u003ctd\u003eRoot Beer\u003c\/td\u003e\n\u003c\/tr\u003e\
n\u003c\/tbody\u003e\u003c\/table\u003e\u003cp\u003e\u003cem\u003eImages are supplied by Argon 18 and may be illustrative. Final specification can vary by region and assembly option.\u003c\/em\u003e\u003c\/p\u003e","published_at":"2026-07-08T16:37:56+01:00","created_at":"2026-07-08T16:37:56+01:00","vendor":"Argon 18","type":"Gravel bike","tags":["Argon 18","Dark Matter","Electronic Shifting","Gravel bike","spo-cs-disabled","spo-default","spo-disabled","spo-notify-me-disabled","SRAM Force XPLR AXS"],"price":650000,"price_min":650000,"price_max":650000,"available":true,"price_varies":false,"compare_at_price":null,"compare_at_price_min":0,"compare_at_price_max":0,"compare_at_price_varies":false,"variants":[{"id":57933586334079,"title":"Root Beer \/ XXS 44-46","option1":"Root Beer","option2":"XXS 44-46","option3":null,"sku":"DM.XXS.373B.2E.1","requires_shipping":true,"taxable":true,"featured_image":{"id":86349319831935,"product_id":15776142033279,"position":2,"created_at":"2026-07-08T16:37:57+01:00","updated_at": "2026-07-08T16:37:59+01:00","alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","width":320,"height":212,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","variant_ids":[57933586334079,57933586366847,57933586399615,57933586432383,57933586465151,57933586497919]},"available":false,"name":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer \/ XXS 44-46","public_title":"Root Beer \/ XXS 44-46","options":["Root Beer","XXS 44-46"],"price":650000,"weight":15000,"compare_at_price":null,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":57933586366847,"title":"Root Beer \/ XS 47-50
","option1":"Root Beer","option2":"XS 47-50","option3":null,"sku":"DM.XS.373B.2E.1","requires_shipping":true,"taxable":true,"featured_image":{"id":86349319831935,"product_id":15776142033279,"position":2,"created_at":"2026-07-08T16:37:57+01:00","updated_at":"2026-07-08T16:37:59+01:00","alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","width":320,"height":212,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","variant_ids":[57933586334079,57933586366847,57933586399615,57933586432383,57933586465151,57933586497919]},"available":false,"name":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer \/ XS 47-50","public_title":"Root Beer \/ XS 47-50","options":["Root Beer","XS 47-50"],"price":650000,"weight":15000,"compare_at_price":null,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":57933586399615,"title":"Root Beer \/ S 51-53","option1":"Root Beer","option2":"S 51-53","option3":null,"sku":"DM.S.373B.2E.1","requires_shipping":true,"taxable":true,"featured_image":{"id":86349319831935,"product_id":15776142033279,"position":2,"created_at":"2026-07-08T16:37:57+01:00","updated_at":"2026-07-08T16:37:59+01:00","alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","width":320,"height":212,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","variant_ids":[57933586334079,57933586366847,57933586399615,57933586432383,57933586465151,57933586497919]},"available":true,"name":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer \/ S 51-53","public_title":"Root Beer \/ S 51-53","options":["Root Beer","S 51-53"],"price":650000,"weight":15000,"comparXXS 44-46e_at_price":null,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":57933586432383,"title":"Root Beer \/ M 54-56","option1":"Root Beer","option2":"M 54-56","option3":null,"sku":"DM.M.373B.2E.1","requires_shipping":true,"taxable":true,"featured_image":{"id":86349319831935,"product_id":15776142033279,"position":2,"created_at":"2026-07-08T16:37:57+01:00","updated_at":"2026-07-08T16:37:59+01:00","alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","width":320,"height":212,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","variant_ids":[57933586334079,57933586366847,57933586399615 ,57933586432383,57933586465151,57933586497919]},"available":true,"name":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer \/ M 54-56","public_title":"Root Beer \/ M 54-56","options":["Root Beer","M 54-56"],"price":650000,"weight":15000,"compare_at_price":null,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":57933586465151,"title":"Root Beer \/ L 57-59","option1":"Root Beer","option2":"L 57-59","option3":null,"sku":"DM.L.373B.2E.1","requires_shipping":true,"taxable":true,"featured_image":{"id":86349319831935,"product_id":15776142033279,"position":2,"created_at":"2026-07-08T16:37:57+01:00","updated_at":"2026-07-08T16:37:59+0
1:00","alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","width":320,"height":212,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","variant_ids":[57933586334079,57933586366847,57933586399615,57933586432383,57933586465151,57933586497919]},"available":false,"name":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer \/ L 57-59","public_title":"Root Beer \/ L 57-59","options":["Root Beer","L 57-59"],"price":650000,"weight":15000,"compare_at_price":null,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}},{"id":57933586497919,"title":"Root Beer \/ XL 60-62","option1":"Root Beer","opt ion2":"XL 60-62","option3":null,"sku":"DM.XL.373B.2E.1","requires_shipping":true,"taxable":true,"featured_image":{"id":86349319831935,"product_id":15776142033279,"position":2,"created_at":"2026-07-08T16:37:57+01:00","updated_at":"2026-07-08T16:37:59+01:00","alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","width":320,"height":212,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","variant_ids":[57933586334079,57933586366847,57933586399615,57933586432383,57933586465151,57933586497919]},"available":false,"name":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer \/ XL 60-62","public_title":"Root Beer \/ XL 60-62","options":["Root Beer","XL 60-62"],"price":650000,"weight":15000,"compare_at_price":null,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/
shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer_666cb537-0ebf-46b4-be04-4174d6c9842f.png?v=1783525081","\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-Force-DM.M.373B.2E.1-Front-Closeup.jpg?v=1783525080","\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-DM.M.373B.2E.1-Closeup-Cockpit_174a62c7-23d3-4c57-8ee4-b0a6f3e37be0.jpg?v=1783525080","\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-DM.M.373B.2E.1-Closeup-Tire-Clearance_23db63b6-0f22-4490-9c67-f490aa6f3ed3.jpg?v=1783525080"],"featured_image":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer_666cb537-0ebf-46b4-be04-4174d6c9842f.png?v=1783525081","options":["Colour","Size"],"media":[{"alt":null,"id":71714643149183,"position":1, "preview_image":{"aspect_ratio":1.501,"height":1364,"width":2048,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer_666cb537-0ebf-46b4-be04-4174d6c9842f.png?v=1783525081"},"aspect_ratio":1.501,"height":1364,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer_666cb537-0ebf-46b4-be04-4174d6c9842f.png?v=1783525081","width":2048},{"alt":"Argon 18 Dark Matter SRAM Force XPLR AXS - Root Beer","id":71714643181951,"position":2,"preview_image":{"aspect_ratio":1.509,"height":212,"width":320,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079"},"aspect_ratio":1.509,"height":212,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/DM.M.373B.2E.1_side-root-beer.png?v=1783525079","width":320},{"alt":null,"id":71714643214719,"position":3,"preview_image":{"aspect_ratio":1.401,"height":1462,"width":2048,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-Force-DM.M.373B.2E.1-Front-Closeu
p.jpg?v=1783525080"},"aspect_ratio":1.401,"height":1462,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-Force-DM.M.373B.2E.1-Front-Closeup.jpg?v=1783525080","width":2048},{"alt":null,"id":71714643247487,"position":4,"preview_image":{"aspect_ratio":1.0,"height":2048,"width":2048,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-DM.M.373B.2E.1-Closeup-Cockpit_174a62c7-23d3-4c57-8ee4-b0a6f3e37be0.jpg?v=1783525080"},"aspect_ratio":1.0,"height":2048,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-DM.M.373B.2E.1-Closeup-Cockpit_174a62c7-23d3-4c57-8ee4-b0a6f3e37be0.jpg?v=1783525080","width":2048},{"alt":null,"id":71714643280255,"position":5,"preview_image":{"aspect_ratio":0.552,"height":2048,"width":1131,"src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-DM.M.373B.2E.1-Closeup-Tire-Clearance_23db63b6-0f22-4490-9c67-f490aa6f3ed3.jpg?v=1783525080"},"aspect_ratio":0.552,"height":2048,"media_type":"image","src":"\/\/projektride.co.uk\/cdn\/shop\/files\/Dark-Matter-DM.M.373B.2E.1-Closeup-Tire-Clearance_23db63b6-0f22-4490-9c67-f490aa6f3ed3.jpg?v=1783525080","width":1131}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003ch2\u003eArgon 18 Dark Matter SRAM Force XPLR AXS\u003c\/h2\u003e\u003cp\u003eThe Dark Matter is a performance gravel platform designed for rugged racing and rough adventure, with modern tyre clearance, stable geometry and practical details for longer mixed-terrain rides.\u003c\/p\u003e\u003cp\u003eThis version is supplied in the SRAM Force XPLR AXS configuration and is available in Root Beer.\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003ePerformance gravel carbon platform\u003c\/li\u003e\n\u003cli\u003eIntegrated cable routing\u003c\/li\u003e\n\u003cli\u003eStorage Optimization System\u003c\/li\u003e\n\u003cli\u003eWide gravel tyre clearance\u003c\/li\u003e\n\u003cli\u003eBuilt for gravel racing and rough adventure riding\u003c\/li\u003e\n\u003cli\u003eAvailable sizes: XXS 44-46, XS 47-50, S 51-53, M 54-56
, L 57-59 and XL 60-62\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eKey specification\u003c\/h3\u003e\u003ctable\u003e\u003ctbody\u003e\n\u003ctr\u003e\n\u003cth\u003eFrame\u003c\/th\u003e\n\u003ctd\u003eDark Matter\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eFork\u003c\/th\u003e\n\u003ctd\u003eDark Matter\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eGroupset\u003c\/th\u003e\n\u003ctd\u003eSRAM Force XPLR AXS E1\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eWheelset\u003c\/th\u003e\n\u003ctd\u003eZIPP 303 XPLR S\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eTyres \/ Clearance\u003c\/th\u003e\n\u003ctd\u003eSchwalbe G-One RX PRO TLR 700x50c\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003cth\u003eColours\u003c\/th\u003e\n\u003ctd\u003eRoot Beer\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\u003c\/table\u003e\u003cp\u003e\u003cem\u003eImages are supplied by Argon 18 and may be illustrative. Final specification can vary by region and assembly option.\u003c\/em\u003e\u003c\/p\u003e"};
window._RestockRocketConfig.variantsInventoryPolicy = {57933586334079 : "deny",57933586366847 : "deny",57933586399615 : "deny",57933586432383 : "deny",57933586465151 : "deny",57933586497919 : "deny",};
window._RestockRocketConfig.variantsInventoryQuantity = {57933586334079 : parseInt("0"),57933586366847 : parseInt("0"),57933586399615 : parseInt("1"),57933586432383 : parseInt("5"),57933586465151 : parseInt("0"),57933586497919 : parseInt("0"),};
window._RestockRocketConfig.variantsPreorderCount = {57933586334079 : parseInt(""),57933586366847 : parseInt(""),57933586399615 : parseInt(""),57933586432383 : parseInt(""),57933586465151 : parseInt(""),57933586497919 : parseInt(""),};
window._RestockRocketConfig.variantsPreorderCountForMarket = {57933586334079 : null,57933586366847 : null,57933586399615 : null,57933586432383 : null,57933586465151 : null,57933586497919 : null,};
window._RestockRocketConfig.variantsPreorderMaxCount
= {57933586334079 : parseInt(""),57933586366847 : parseInt(""),57933586399615 : parseInt(""),57933586432383 : parseInt(""),57933586465151 : parseInt(""),57933586497919 : parseInt(""),};
window._RestockRocketConfig.variantsPreorderMaxCountForMarket = {57933586334079 : null,57933586366847 : null,57933586399615 : null,57933586432383 : null,57933586465151 : null,57933586497919 : null,};
window._RestockRocketConfig.variantsShippingText = {57933586334079 : "",57933586366847 : "",57933586399615 : "",57933586432383 : "",57933586465151 : "",57933586497919 : "",};
window._RestockRocketConfig.variantsShippingTextForMarket = {57933586334079 : null,57933586366847 : null,57933586399615 : null,57933586432383 : null,57933586465151 : null,57933586497919 : null,};
window._RestockRocketConfig.selected_variant_id = 57933586399615;
window._RestockRocketConfig.selected_variant_available = window._RestockRocketConfig.product.variants.find(function(variant) { return variant.id == window._RestockRocketConfig.selected_variant_id }).available;// STOQ-1595/1612 shared signal, derived once here so both the accelerated-checkout block
// gate (STOQ-1612) and the click tracker (STOQ-1595) read one clearly-owned flag rather
// than a side effect buried in either consumer's try/catch: whether this shop has preorders
// configured at all — an enabled selling plan plus at least one preorder variant id,
// independent of the block toggle. Fail-open: on error the flag stays unset and both
// consumers no-op.
try {
var _sqCfg = window._RestockRocketConfig;
var _sqPlanEnabled = Array.isArray(_sqCfg.sellingPlans) &&
_sqCfg.sellingPlans.some(function (p) { return p && p.enabled; });
var _sqPreCount = ((_sqCfg.cachedPreorderVariantIds &&
_sqCfg.cachedPreorderVariantIds.preorder_variant_ids) || []).length;
_sqCfg.preordersConfigured = !!(_sqPlanEnabled && _sqPreCount);
} catch (e) { /* fail open */ }
// STOQ-1612: block (not hide) Buy Now / Shop Pay until our JS runs, so a tap in the
// lXS 47-50oad window can't bypass preorder. pointer-events via .stoq-buy-now-pending (no
// reflow); timeout releases; renderPreorderButton / featured_product.js lift it.
// Gated by the `block_accelerated_checkout` toggle (default OFF) for gradual rollout.
// Armed ONLY when we're sure preorder is in play — product page: THIS product has a
// preorder variant (never block a plain product's Shop Pay); featured: integration
// enabled for this page type. Rationale: PR #2784.
try {
var _sqc = window._RestockRocketConfig;
var _sqOn = !!(_sqc.cachedSettings && _sqc.cachedSettings.block_accelerated_checkout);
var _sqPre = (_sqc.cachedPreorderVariantIds &&
_sqc.cachedPreorderVariantIds.preorder_variant_ids) || [];
var _sqArm = false;
if (_sqOn && _sqc.preordersConfigured) {
if (_sqc.pageType === 'product' && _sqc.product && _sqc.product.variants) {
_sqArm = _sqc.product.variants.some(function (v) { return _sqPre.indexOf(Number(v.id)) !== -1; });
} else {
_sq Arm = (_sqc.integrations || []).some(function (i) {
return i && i.type === 'featured_product' && i.enabled &&
Array.isArray(i.page_types) && i.page_types.indexOf(_sqc.pageType) !== -1;
});
}
}
if (_sqArm && document.documentElement) {
_sqc.acceleratedGateArmed = true;
document.documentElement.classList.add('stoq-buy-now-pending');
setTimeout(function () {
document.documentElement.classList.remove('stoq-buy-now-pending');
}, 6000);
}
} catch (e) { /* fail open */ }
window._RestockRocketConfig.scriptUrlProduct = 'https://cdn.shopify.com/extensions/019faaab-f88c-7089-ae75-a5669aee845c/restockrocket-1-553/assets/restockrocket-product.js'
window._RestockRocketConfig.scriptUrlCollection = 'https://cdn.shopify.com/extensions/019faaab-f88c-7089-ae75-a5669aee845c/restockrocket-1-553/assets/restockrocket-collection.js'
window._RestockRocketConfig.scriptUrlProductBis = 'https://cdn.shopify.com/extensions/019faaab-f88c-7089-ae75-a566
9aee845c/restockrocket-1-553/assets/restockrocket-product-bis.js'
window._RestockRocketConfig.scriptUrlCollectionBis = 'https://cdn.shopify.com/extensions/019faaab-f88c-7089-ae75-a5669aee845c/restockrocket-1-553/assets/restockrocket-collection-bis.js'
window._RestockRocketConfig.scriptHost = window._RestockRocketConfig.scriptUrlProduct.substring(0, window._RestockRocketConfig.scriptUrlProduct.lastIndexOf('/') + 1)
// Canary override (STOQ-1287): prefer the Render host emitted into the
// metafield-cached settings (api_host) when present, mirroring the same
// override in assets/js/api.js. cachedSettings is populated above. Falls
// back to the build-baked host for shops without the use_render_api_host
// toggle (or environments where THEME_EXTENSION_API_HOST is unset), so the
// setting.json + fetchEmbedConfig calls below route to the same host as the
// rest of the extension's API traffic instead of staying on the baked host.
window._RestockRocketConfig.host = (window._RestockRocketConfig .cachedSettings && window._RestockRocketConfig.cachedSettings.api_host) || 'https://app.restockrocket.io'
// Deployed extension build number, read from the CDN asset host Shopify generates:
// https://cdn.shopify.com/extensions/
< uuid>/
<handle>-
< version>/assets/...
// Trailing digits (e.g. ".../restockrocket-1-521/assets/" -> "521"). Kept numeric to
// match ParseStoqData, so funnel app_version lines up with the order-attribution
// app_version. Reflects the ACTUAL deployed build. This is the SINGLE source of the
// parsed version — preorder.js getAppVersion() reads it back off config rather than
// re-parsing, so the regex lives in exactly one place.
try {
const _stoqVersionMatch = window._RestockRocketConfig.scriptHost.match(/(\d+)\/?(?:assets\/?)?$/);
window._RestockRocketConfig.appVersion = (_stoqVersionMatch && _stoqVersionMatch[1]) || '';
} catch (e) {
window._RestockRocketConfig.appVersion = '';
}
const SETTINGS_CACHE_DURATION = 15 * 60 * 1000; // 15 minutes in milliseconds
const LIQUID_CACHE_MAX_AGE = 15 * 60; // 15 minutes in seconds
// Calculate Liquid cache freshness once at initialization
const liquidRenderedAt = window._RestockRocketConfig.liquidRenderedAt;
// Validate timestamp and calculate ca
che age
if (!liquidRenderedAt || typeof liquidRenderedAt !== 'number' || isNaN(liquidRenderedAt)) {
console.debug('STOQ - Invalid or missing liquidRenderedAt timestamp, assuming fresh');
window._RestockRocketConfig.isLiquidCacheFresh = true;
window._RestockRocketConfig.liquidCacheAge = null;
} else {
const now = Math.floor(Date.now() / 1000); // Current time in seconds
const liquidCacheAge = now - liquidRenderedAt; // Age in seconds
// Surfaced into funnel events: a stale cache means the app rendered with
// outdated inventory/selling-plan data — a real "had the opportunity but
// failed" cause. Negative (client clock ahead) clamps to 0.
window._RestockRocketConfig.liquidCacheAge = Math.max(0, liquidCacheAge);
// Handle client clock ahead of server
if (liquidCacheAge <
= LIQUID_CACHE_MAX_AGE) {
console.debug(`STOQ - Liquid cache is fresh (${Math.round(liquidCacheAge / 60)} minutes old)`);
window._RestockRocketConfig.isLiquidCacheFresh = true;
} else {
console.debug(`STOQ - Liquid cache is stale (${Math.round(liquidCacheAge / 60)} minutes old, max ${Math.round(LIQUID_CACHE_MAX_AGE / 60)} minutes)`);
window._RestockRocketConfig.isLiquidCacheFresh = false;
}
}
function checkSettingsExpiry(settings) {
try {
if (!settings || !settings.updated_at) {
console.debug('STOQ - Invalid settings data structure');
return null;
}
if (!settings.cache) {
console.debug('STOQ - settings caching disabled');
return null;
}
// Check if translations are enabled but missing from cache
// This handles the backfill period where DB has translations but metafield doesn't
if (settings.multi_language_enabled) {
if (!settings.translations) {
// Translations enabled but no
translation data in metafield
// Metafield hasn't been backfilled yet - force refresh
console.debug('STOQ - multi-language enabled but no translation data in cache, fetching fresh');
return null;
}
// Translations object exists in metafield - cache is valid
// If current locale isn't translated, applyTranslations will gracefully use default locale from base fields
if (window._RestockRocketConfig.normalizedLocale &&
!Object.prototype.hasOwnProperty.call(settings.translations, window._RestockRocketConfig.normalizedLocale)) {
console.debug('STOQ - locale not explicitly translated, will use default language from cache');
}
// Don't return null - continue using cache even for untranslated locales
}
const updatedAt = new Date(settings.updated_at);
if (isNaN(updatedAt.getTime())) {
console.debug('STOQ - Invalid updated_at date format in settings');
return null;
}
const age = Date.now() - updatedAt.getTime();
if (age
< SETTINGS_CACHE_DURATION) {
console.debug('STOQ - settings changed recently, skipping cache');
return null;
}
return settings;
} catch (error) {
console.debug('STOQ - Error checking settings cache:', error);
return null;
}
}
function createRestockRocketContainer() {
const restockRocketContainer = document.createElement('div');
restockRocketContainer.id = 'restock-rocket';
document.body.appendChild(restockRocketContainer);
}
function createRestockRocketScript(scriptUrl) {
const restockRocketScriptElement = document.createElement('script');
restockRocketScriptElement.setAttribute('defer', 'defer');
restockRocketScriptElement.src = scriptUrl;
document.body.appendChild(restockRocketScriptElement);
}
createRestockRocketContainer()
console.debug('STOQ - extension activated')
// Fire stoq_initialized once per page load so the funnel pipeline has a definitive
// "our code ran on this page" signal independent of any cus
tomer interaction.
// Detected variants: the variants present in this page's Liquid context (product page has them;
// collection/index/etc. don't expose variants from Liquid). Used to disambiguate "embed didn't
// load" vs "embed loaded but the variant wasn't a preorder/BIS candidate" in order debug.
try {
const _stoqInitConfig = window._RestockRocketConfig;
const _stoqDetectedVariantIds = (_stoqInitConfig.product && Array.isArray(_stoqInitConfig.product.variants))
? _stoqInitConfig.product.variants.map(function(v) { return v.id })
: [];
const _stoqSelectedVariantId = _stoqInitConfig.selected_variant_id;
// Per-session page-load counter, incremented here in the INLINE code so it exists
// even when the deferred bundle never runs. Paired with stoq_bundle_ready's
// page_load_seq, it tells order-debug which page load an add fired on (and whether
// the bundle had loaded on that load).
var _stoqPageSeq = 0;
try {
_stoqPageSeq = (parseInt(window.sessi onStorage.getItem('_stoq_pls') || '0', 10) || 0) + 1;
window.sessionStorage.setItem('_stoq_pls', String(_stoqPageSeq));
} catch (e) { /* sessionStorage unavailable (private mode) — leave 0 */ }
Shopify?.analytics?.publish?.('stoq_initialized', {
cart_token: _stoqInitConfig.cartToken || '',
page_url: window.location.href,
page_type: _stoqInitConfig.pageType || '',
shop_domain: _stoqInitConfig.shop || '',
market_id: _stoqInitConfig.marketId || '',
// Buyer's storefront country (localization.country.iso_code). Seeds the
// pixel's extension_details blob so it rides forward onto Shopify's native
// events too — a market can span countries, so this is the finer signal.
country_code: _stoqInitConfig.countryIsoCode || '',
detected_variant_ids: _stoqDetectedVariantIds,
selected_variant_id: _stoqSelectedVariantId || '',
page_load_seq: _stoqPageSeq,
liquid_rendered_at: _stoqInitConfig.liquidRenderedAt || 0,
app_version
: _stoqInitConfig.appVersion || '',
liquid_cache_age: _stoqInitConfig.liquidCacheAge,
// Selected variant's stock posture as our app saw it at render — explains
// whether we *should* have treated it as a preorder candidate.
inventory_policy: (_stoqInitConfig.variantsInventoryPolicy || {})[_stoqSelectedVariantId] || '',
inventory_quantity: (_stoqInitConfig.variantsInventoryQuantity || {})[_stoqSelectedVariantId],
});
} catch (e) {
console.debug('STOQ - stoq_initialized publish failed:', e);
}
// STOQ-1595: publish stoq_accelerated_checkout_clicked for every accelerated-checkout
// click (Buy Now / dynamic checkout / Shop Pay installments) on ALL surfaces, before our
// bundle loads, via one delegated capture-phase listener (catches late-rendered buttons).
// Only on shops with preorders configured (shared `preordersConfigured` signal from the
// derivation block above) — nothing to bypass otherwise. variant_id is read per-clicked-button
// from its form so it's correct on collection/index/search too. block_accelerated_checkout
// context (STOQ-1612) rides in `properties` (forwarded verbatim by the pixel, no schema
// change): a buy_now click on a preorder variant while the gate was armed is a visible
// bypass signal for order debug. Also sends page_url (top-level, like the pixel's native
// events) and two preorder signals in properties (see below).
try {
var _sqTrack = window._RestockRocketConfig;
if (_sqTrack.preordersConfigured) {
document.addEventListener('click', function (e) {
try {
var t = e.target;
if (!t || !t.closest) return;
var host = t.closest('.shopify-payment-button, shopify-payment-terms');
if (!host) return;
var channel = host.matches && host.matches('shopify-payment-terms')
? 'shop_pay_installments' : 'buy_now';
var form = host.closest('form');
var vidEl = form && form.querySelector('[name="id"]');
var variantId = M 54-56(vidEl && vidEl.value) || _sqTrack.selected_variant_id || '';
// The enabled STOQ selling plan the clicked variant belongs to (if any), found once and
// reused for in_enabled_plan / enrolled_plan_id / enrolled_plan_provider below.
var _sqVidNum = Number(variantId);
var _sqPlan = null;
// Array.isArray guard (not `|| []`) so a truthy non-array sellingPlans can't throw and
// silently drop the whole publish.
var _sqPlans = Array.isArray(_sqTrack.sellingPlans) ? _sqTrack.sellingPlans : [];
_sqPlans.forEach(function (pl) {
if (!_sqPlan && pl && pl.enabled && Array.isArray(pl.variant_ids) &&
pl.variant_ids.indexOf(_sqVidNum) !== -1) { _sqPlan = pl; }
});
Shopify?.analytics?.publish?.('stoq_accelerated_checkout_clicked', {
variant_id: variantId,
product_id: (_sqTrack.product && _sqTrack.product.id) || '',
channel: channel,
market_id: _sqTrac k.marketId || '',
country_code: _sqTrack.countryIsoCode || '',
page_type: _sqTrack.pageType || '',
cart_token: _sqTrack.cartToken || '',
page_url: (window.location && window.location.href) || '',
properties: {
// Mirror the bundle's own preorder check (preorder.js checkInventoryProvider-
// WithCachedFallback): the live set config.preorderVariantIds (refreshed after
// page load by loadVariantInventoryData) OR the Liquid-injected
// cachedPreorderVariantIds — always present, so it covers clicks before the
// bundle loads (why this tracker is inline). ORing both (not preferring one)
// matches the bundle and is correct even if the live set is an empty array. Both
// hold integer ids; the click-time id comes off a DOM input (.value → string) or
// selected_variant_id, so coerce with Number for a like-typed compare.
is_preord
er_variant: (function () {
var vid = Number(variantId);
var has = function (a) { return Array.isArray(a) && a.indexOf(vid) !== -1; };
return has(_sqTrack.preorderVariantIds) ||
has(_sqTrack.cachedPreorderVariantIds &&
_sqTrack.cachedPreorderVariantIds.preorder_variant_ids);
})(),
// Narrow, authoritative preorder signal: enrolled in an ENABLED STOQ selling plan
// (is_preorder_variant above is the broad OOS+continue heuristic — non-STOQ too).
in_enabled_plan: !!_sqPlan,
// In-stock preorder signal: enrolled but currently IN STOCK (in the inStockVariantIds
// set, not the OOS preorderVariantIds set). Same live-OR-cached pattern as
// is_preorder_variant. is_preorder_variant OR is_instock_variant = "should sell via
// the plan" regardless of stock, so an in-stock preorder bypass is detectable too.
is_ instock_variant: (function () {
var has = function (a) { return Array.isArray(a) && a.indexOf(_sqVidNum) !== -1; };
return has(_sqTrack.inStockVariantIds) ||
has(_sqTrack.cachedInStockVariantIds &&
_sqTrack.cachedInStockVariantIds.in_stock_variant_ids);
})(),
// The enrolled plan's Shopify selling-plan id + inventory_provider (stoq = STOQ tracks
// the OOS count; shopify = in-stock preorder). Tells order-debug what kind of preorder
// the Buy Now bypassed, without a downstream lookup.
enrolled_plan_id: (_sqPlan && (_sqPlan.shopify_selling_plan_id || _sqPlan.shopify_selling_plan_group_id)) || '',
enrolled_plan_provider: (_sqPlan && _sqPlan.inventory_provider) || '',
block_enabled: !!(_sqTrack.cachedSettings && _sqTrack.cachedSettings.block_accelerated_checkout),
gate_armed: !!_sqTrack.acceleratedGateArmed,
gate_active
_at_click: !!(document.documentElement &&
document.documentElement.classList.contains('stoq-buy-now-pending')),
},
});
} catch (err) { /* never break checkout */ }
}, true);
}
} catch (e) { /* fail open */ }
function applyTranslations(settings) {
try {
// Skip translation logic entirely if multi-language is not enabled
if (!settings || !settings.multi_language_enabled) {
return settings;
}
if (!settings.translations) {
console.debug('STOQ - No translations found, skipping translation');
return settings;
}
const normalizedLocale = window._RestockRocketConfig.normalizedLocale;
const translations = settings.translations;
if (!normalizedLocale) {
// No matching locale has translations; drop payload to save memory
console.debug('STOQ - No matching locale for translations. Available:', Object.keys(translations || {}));
delete settings.translations;
return settings;
}
console.debug(`STOQ - Applying translations for normalized locale: ${normalizedLocale} (original: ${window._RestockRocketConfig.locale})`);
const translatedFields = translations[normalizedLocale];
if (translatedFields && typeof translatedFields === 'object') {
Object.keys(translatedFields).forEach(function(key) {
const value = translatedFields[key];
if (value !== null && value !== undefined && value !== '') {
settings[key] = value;
}
});
} else {
console.debug('STOQ - No translated fields found for locale:', normalizedLocale);
}
delete settings.translations;
return settings;
} catch (e) {
console.debug('STOQ - error applying translations:', e);
return settings;
}
}
// Setup event listener for cart selling plan updates
// This must be called before any scripts are loaded to avoid race conditions
function setupCartSellingPlanUpdater(settings) {
// Setup listener regardless - updateCartSellingPlans has its own guards
// This ensures cleanup happens even when preorders are disabled globally
// Listen for stoq:inventory-data-loaded event dispatched by api.js
window.addEventListener('stoq:inventory-data-loaded', function(event) {
console.debug('STOQ - Inventory data loaded, updating cart selling plans');
if (window._RestockRocket && window._RestockRocket.updateCartSellingPlans) {
window._RestockRocket.updateCartSellingPlans()
.then(hasUpdates => {
if (hasUpdates) {
console.debug('STOQ - cart selling plans updated successfully');
} else {
console.debug('STOQ - no cart selling plan updates needed');
}
})
.catch(error => {
console.error('STOQ - error updating cart selling plans:', error);
});
}
});
}
// ---- Live settings via the Storefront API (additive, does not gate init) ----
// The inlined `cachedSettings` comes from the app-embed Liquid render, which
// Shopify edge-caches and can serve stale. Reading the same `settings` metafield
// back over the Storefront API is a POST to /api/
< version>/graphql.json — never
// CDN-cached — so it returns the live value on every page load. We fetch it
// best-effort and stash it on `window._RestockRocketConfig.storefrontSettings`
// so individual behaviours can migrate onto the fresh value over time. This is
// PURELY ADDITIVE: it does NOT change the resolution flow below, never blocks
// init, and silently no-ops on any failure / missing token.
(function loadStorefrontSettings() {
const cfg = window._RestockRocketConfig;
if (!cfg.storefrontAccessToken || cfg.disableStorefrontApi === true) return;
// Deferred to browser idle so this best-effort read runs strictly AFTER the
// critical init flow and never competes with it for a connection — the call
// is a live, uncached Storefront round-trip and can be slow (multi-second
// TTFB observed). Nothing on the critical path waits for it.
function run() {
const query = 'query StoqSettings($namespace: String!) { shop { metafield(namespace: $namespace, key:
"settings") { value } } }';
fetch(
`https://${cfg.shop}/api/2025-07/graphql.json`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': cfg.storefrontAccessToken,
},
body: JSON.stringify({ query: query, variables: { namespace: cfg.metafieldNamespace } }),
}
)
.then(function(response) {
if (!response.ok) { throw new Error('Storefront API HTTP ' + response.status); }
return response.json();
})
.then(function(body) {
if (body && body.errors && body.errors.length) {
throw new Error('Storefront API errors: ' + body.errors.map(function(e) { return e && e.message; }).join(', '));
}
const value = body && body.data && body.data.shop && body.data.shop.metafield && body.data.shop.metafield.value;
if (!value) { throw new Error('Storefront API returned no settings metafield value'); }
cfg.storefrontSettings = JSON.parse(value);
console.debug('STOQ - stored live settings from Storefront API on config.storefrontSettings');
})
.catch(function(e) {
console.debug('STOQ - Storefront settings fetch failed (non-fatal):', e && e.message);
});
}
if (typeof window.requestIdleCallback === 'function') {
window.requestIdleCallback(run, { timeout: 5000 });
} else {
setTimeout(run, 0);
}
})();
// First try to get settings from metafields with expiry check
const cachedSettings = window._RestockRocketConfig.cachedSettings;
const validCachedSettings = cachedSettings ? checkSettingsExpiry(cachedSettings) : null;
if (validCachedSettings) {
console.debug('STOQ - using cached settings');
initializeScripts(validCachedSettings);
} else {
console.debug('STOQ - fetching fresh settings');
const headers = {
'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.Shopify.shop,
'ngrok-skip-browser-warning': 'skiL 57-59p'
};
if (window.Shopify?.theme?.role === 'main') {
headers['X-Shopify-Theme-Schema-Name'] = window.Shopify.theme.schema_name;
headers['X-Shopify-Theme-Schema-Version'] = window.Shopify.theme.schema_version;
headers['X-Shopify-Theme-Store-Id'] = window.Shopify.theme.theme_store_id;
}
fetch(
`${window._RestockRocketConfig.host}/api/v1/setting.json?translation_locale=${window._RestockRocketConfig.normalizedLocale}`,
{ headers }
)
.then(function(response) {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(function(settings) {
initializeScripts(settings);
})
.catch(function(error) {
// If request failed and we have cached settings (even if expired), use them as fallback
if (cachedSettings) {
console.debug('STOQ - using expired cached settings as fallback');
initializeScripts(cachedSettings);
} else {
console.error('S TOQ - failed to load settings:', error);
}
})
.catch(function(e) {
console.error(e)
})
}
function fetchEmbedConfig(endpoint, apply) {
return fetch(
`${window._RestockRocketConfig.host}/api/v1/embed/${endpoint}.json`,
{
headers: {
'X-Shopify-Shop-Domain': window._RestockRocketConfig.shop || window.Shopify.shop,
'ngrok-skip-browser-warning': 'skip'
}
}
)
.then(function(response) {
if (!response.ok) throw new Error(`Failed to fetch ${endpoint}`);
return response.json();
})
.then(function(data) {
try {
apply(data);
} catch (applyError) {
// Apply failures are programming bugs (e.g. response shape changed
// server-side and the assignment threw). Surface them as console.error
// so they're visible in browser logs, then re-throw to fall through
// to the same Liquid-cached fallback as a fetch failure.
console.error('STOQ - apply failed for ' +
endpoint + ':', applyError);
throw applyError;
}
})
.catch(function(error) {
console.debug(`STOQ - using cached ${endpoint}:`, error.message);
});
}
function initializeScripts(settings) {
settings = applyTranslations(settings);
window._RestockRocketConfig.settings = settings;
console.debug(`STOQ - settings configured for ${window._RestockRocketConfig.pageType}`);
// Stale-Liquid resilience (default-on, per-shop opt-out via the
// `disable_refresh_on_stale_liquid` Toggle, surfaced as the negative
// `disable_refresh_on_stale_liquid` flag in settings.json so that
// `undefined` -- in CDN-cached metafield payloads that predate this
// key -- reads as `!undefined === true` and gets default-on behavior
// immediately, no metafield rewrite required).
// When the Liquid CDN cache is older than LIQUID_CACHE_MAX_AGE the in-page
// selling_plans / integrations metafields can be wrong; refresh both from
// the API before launching scr ipts. Race against a 1000ms timeout so a slow
// API can't block init indefinitely. If the timeout wins, the in-flight
// fetches still complete and update window._RestockRocketConfig — the
// bundle re-reads sellingPlans/integrations on every interaction, so the
// late-arriving values benefit subsequent renders even though the first
// paint may use the Liquid-cached values. On any failure the existing
// Liquid-loaded values stay in place via fetchEmbedConfig's catch.
if (!window._RestockRocketConfig.isLiquidCacheFresh && !settings.disable_refresh_on_stale_liquid) {
console.debug('STOQ - Liquid cache stale, refreshing selling_plans + integrations');
Promise.race([
Promise.all([
fetchEmbedConfig('selling_plans', function(data) {
if (data && Array.isArray(data.plans)) {
window._RestockRocketConfig.sellingPlans = data.plans;
window._RestockRocketConfig.disabledSellingPlanIds = data.disabled_plan_ids || [];
}
}),
fetchEmbedConfig('integrations', function(data) {
if (Array.isArray(data)) {
window._RestockRocketConfig.integrations = data;
}
})
]),
new Promise(function(resolve) { setTimeout(resolve, 1000); })
]).then(function() { loadScripts(settings); });
return;
}
loadScripts(settings);
}
function loadScripts(settings) {
// Setup cart selling plan updater BEFORE loading any scripts to avoid race conditions
setupCartSellingPlanUpdater(settings);
if(settings.enable_app) {
const hijackIntegration = window._RestockRocketConfig.integrations.find(function(integration) {
return integration.type === 'hijack' && integration.enabled && integration.page_types.includes(window._RestockRocketConfig.pageType);
})
// STOQ-1520: serve the lean back-in-stock-only build (no preorder/hijack code)
// only to shops with NO preorder plans. Use the full build if preorder is o n,
// an enabled offer exists, or a disabled-but-kept plan id remains (cart sweep
// must still strip those). Rationale in the PR.
const hasEnabledOffer = Array.isArray(window._RestockRocketConfig.sellingPlans)
&& window._RestockRocketConfig.sellingPlans.some(function(plan) { return plan && plan.enabled; });
const hasDisabledPlanIds = Array.isArray(window._RestockRocketConfig.disabledSellingPlanIds)
&& window._RestockRocketConfig.disabledSellingPlanIds.length > 0;
const usePreorderBuild = settings.preorder_enabled || hasEnabledOffer || hasDisabledPlanIds;
const collectionScriptUrl = usePreorderBuild
? window._RestockRocketConfig.scriptUrlCollection
: window._RestockRocketConfig.scriptUrlCollectionBis;
const productScriptUrl = usePreorderBuild
? window._RestockRocketConfig.scriptUrlProduct
: window._RestockRocketConfig.scriptUrlProductBis;
const pageType = window._RestockRocketConfig.pageType;
const collecti
onPageTypes = ['collection', 'index', 'search', 'page'];
if(collectionPageTypes.indexOf(pageType) !== -1 && (settings[`show_button_on_${pageType}`] || settings[`preorder_${pageType}_enabled`])) {
createRestockRocketScript(collectionScriptUrl);
} else if(pageType === 'product') {
createRestockRocketScript(productScriptUrl);
} else if(hijackIntegration) {
createRestockRocketScript(window._RestockRocketConfig.scriptUrlCollection);
} else if(usePreorderBuild) {
// cart/article/blog/list-collections: full build so the cart sweep runs.
createRestockRocketScript(window._RestockRocketConfig.scriptUrlCollection);
} else {
console.debug(`STOQ - no scripts enabled for ${pageType}`);
}
// Dispatch custom event when app is loaded
// Cart selling plan updates will be triggered by stoq:inventory-data-loaded event
const appLoadedEvent = new CustomEvent('stoq:loaded', {
detail: {
pageType: window._RestockR
html.stoq-buy-now-pending .shopify-payment-button{pointer-events:none!important}.stoq-hide-buy-now .shopify-payment-button,.stoq-hide-buy-now shopify-payment-terms,.stoq-hide-buy-now .shopify-payment-terms{display:none!important}.restock-rocket-button,.restock-rocket-button-float{opacity:1!important;border:none!important;cursor:pointer!important;background-image:none!important;box-shadow:none!important;padding:15px 20px;font-size:16px;width:100%;font-family:inherit}@font-face{font-family:OpenSans;font-weight:200;src:url(https://d382hokyqag45a.cloudfront.net/assets/OpenSans-Light.woff)}@font-face{font-family:OpenSans;font-weight:300;src:url(https://d382hokyqag45a.cloudfront.net/assets/OpenSans-Regular.woff)}@font-face{font-family:OpenSans;font-weight:600;src:url(https://d382hokyqag45a.cloudfront.net/assets/OpenSans-SemiBold.woff)}.restock-rocket-button-container{position:relative;z-index:1;width:100%}.restock-rocket-button-container-float-right{position:fixed;z-index:123123;top:calc(50% - 200px);right:0;transform:rotate(270deg);transform-origin:bottom right}.restock-rocket-button-container-float-left{position
:fixed;z-index:123123;top:calc(50% - 200px);left:40px;transform:rotate(90deg);transform-origin:top left}.restock-rocket-button-container-float-left:hover,.restock-rocket-button-container-float-right:hover,.restock-rocket-button-container:hover,.restock-rocket-button-float:hover,.restock-rocket-button:hover{opacity:.8}.restock-rocket-button{min-height:50px;margin-top:10px;margin-bottom:10px}.restock-rocket-button-collection{position:relative;font-size:13px;line-height:1;padding:7px;height:auto;z-index:3}.restock-rocket-wrapper{background-color:rgba(0,0,0,.5);z-index:123123123;width:100%;height:100%;overflow:auto;position:fixed;right:0;top:0;transition-property:all;transition-duration:.3s;display:flex;flex-direction:column;justify-content:center;}.restock-rocket-wrapper-inline{width:100%;height:100%;margin-top:20px}.restock-rocket-preorder-description{padding:10px 15px;margin-top:20px;display:flex;flex-direction:column;gap:10px;}.preorder-description-details{margin-bottom:0;display:flex;flex-direction:column;ga p:10px;}.preorder-detail-item{display:flex;flex-direction:row;justify-content:start;gap:8px;align-items:center;}.restock-rocket-payment-widget{border:1px solid #ebebeb;margin-bottom:20px;}.restock-rocket-payment-option{display:flex;flex-wrap:wrap;align-items:center;gap:5px;padding:15px 20px;}.restock-rocket-payment-option:not(:last-child){border-bottom:1px solid #ebebeb;}.restock-rocket-payment-input-container{flex:1 1 auto;min-width:0}.restock-rocket-preorder-discount-badge{background:#ebebeb;height:25px;line-height:25px;padding:0 15px;border-radius:25px;font-size:0.8rem;flex:0 0 auto}.restock-rocket-payment-input{margin-right:10px;margin-top:-3px;vertical-align:middle;margin-left:0;accent-color:#202223}.restock-rocket-payment-description{margin-top:4px;flex:1 1 100%}.restock-rocket-preorder-badge{font-size:13px;line-height:1;padding:5px 13px 6px;border-radius:40px;height:auto;border:none;width:auto;z-index:2;margin:0;background:0 0}.preorder-badge-collection{position:absolute;top:10px;right:10px}.preorder-b
adge-product{margin-left:10px}.restock-rocket-price-strike{text-decoration:line-through;color: #666666;}.restock-rocket-discounted-price{margin-left:10px;}.restock-rocket-acknowledgement-checkbox{margin-bottom:12px;display:flex;align-items:flex-start;gap:8px;font-size:14px;line-height: 1.5;}.restock-rocket-acknowledge-checkbox-input{width:18px;height:18px;margin-top:2px;cursor:pointer;flex-shrink:0;accent-color: #0d0d0d;}.restock-rocket-acknowledge-checkbox-label{flex:1;cursor:pointer;}.restock-rocket-preorder-countdown-timer{display:flex;flex-direction:column;align-items:center;padding:16px;margin:8px 0;font-family:inherit;}.restock-rocket-preorder-countdown-timer .countdown-header{font-size:16px;margin-bottom:6px;text-align:center}.restock-rocket-preorder-countdown-timer .countdown-units{display:flex;flex-wrap:wrap;gap:12px;justify-content:center}.restock-rocket-preorder-countdown-timer .countdown-unit{display:flex;flex-direction:column;align-items:center;gap:6px}.restock-rocket-preorder-countdown-timer .co untdown-box{min-width:40px;padding:10px 6px;text-align:center;font-size:20px;line-height:1}.restock-rocket-preorder-countdown-timer .countdown-label{font-size:14px;font-weight:500;text-align:center;text-transform:capitalize;opacity:.7}@media (max-width:768px){.restock-rocket-preorder-countdown-timer{padding:14px}.restock-rocket-preorder-countdown-timer .countdown-box{min-width:55px;padding:14px 10px;font-size:26px}.restock-rocket-preorder-countdown-timer .countdown-label{font-size:11px}}@media (max-width:480px){.restock-rocket-preorder-countdown-timer{padding:12px}.restock-rocket-preorder-countdown-timer .countdown-units{width:100%;gap:10px}.restock-rocket-preorder-countdown-timer .countdown-box{width:100%;min-width:50px;padding:12px 8px;font-size:24px}.restock-rocket-preorder-countdown-timer .countdown-label{font-size:10px}}.restock-rocket-toast{position:fixed;cursor:pointer;background:#fff;border:0;min-width:40px;min-height:40px;box-shadow:0 0 15px rgba(0,0,0,.1)!important;z-index:622004;padding:20px 30px;f
ont-family:inherit;font-size:inherit;color:#000;display:flex;justify-content:center;align-items:center}.restock-rocket-toast a{text-decoration:none;font-weight:700;color:#000}.restock-rocket-toast .dismiss{margin-left:15px;z-index:1;font-size:20px;}.restock-rocket-toast-top{top:60px}.restock-rocket-toast-bottom{bottom:75px}.restock-rocket-toast-left,.restock-rocket-toast-right{-webkit-animation:.5s forwards slide;animation:.5s forwards slide}.restock-rocket-toast-left{left:0;transform:translateX(-100%);-webkit-transform:translateX(-100%);border-radius:0 10px 10px 0}.restock-rocket-toast-left.slide-out{-webkit-animation:.5s forwards slide-out-left;animation:.5s forwards slide-out-left}.restock-rocket-toast-right{right:0;transform:translateX(100%);-webkit-transform:translateX(100%);border-radius:10px 0 0 10px}.restock-rocket-toast-right.slide-out{-webkit-animation:.5s forwards slide-out-right;animation:.5s forwards slide-out-right}@keyframes slide{100%{transform:translateX(0)}}@-webkit-keyframes slide{100%{-web
kit-transform:translateX(0)}}@keyframes slide-out-left{0%{transform:translateX(0)}100%{transform:translateX(-100%)}}@-webkit-keyframes slide-out-left{0%{-webkit-transform:translateX(0)}100%{-webkit-transform:translateX(-100%)}}@keyframes slide-out-right{0%{transform:translateX(0)}100%{transform:translateX(100%)}}@-webkit-keyframes slide-out-right{0%{-webkit-transform:translateX(0)}100%{-webkit-transform:translateX(100%)}}.restock-rocket-preorder-progress-bar{padding:12px 15px;margin-bottom:20px;font-family:inherit;}.restock-rocket-preorder-progress-bar .preorder-progress-text{margin-bottom:8px;}.restock-rocket-preorder-progress-bar .preorder-progress-bar-row{display:flex;align-items:center;gap:10px;}.restock-rocket-preorder-progress-bar .preorder-progress-track{flex:1;height:12px;overflow:hidden;}.restock-rocket-preorder-progress-bar .preorder-progress-fill{display:block;height:100%;min-width:2px;transition:width 0.3s ease;}.restock-rocket-preorder-progress-bar .preorder-progress-percentage{font-weight:500;mi
n-width:35px;text-align:right;}