com/extensions/019cd40b-736e-74a5-adbe-431365bfd910/restockrocket-1-465/assets/restockrocket-collection.js'
window._RestockRocketConfig.scriptHost = window._RestockRocketConfig.scriptUrlProduct.substring(0, window._RestockRocketConfig.scriptUrlProduct.lastIndexOf('/') + 1)
window._RestockRocketConfig.host = 'https://app.restockrocket.io'
const SETTINGS_CACHE_DURATION = 15 * 60 * 1000; // 15 minutes in milliseconds
const LIQUID_CACHE_MAX_AGE = 2 * 60 * 60; // 2 hours in seconds
// Calculate Liquid cache freshness once at initialization
const liquidRenderedAt = window._RestockRocketConfig.liquidRenderedAt;
// Validate timestamp and calculate cache age
if (!liquidRenderedAt || typeof liquidRenderedAt !== 'number' || isNaN(liquidRenderedAt)) {
console.debug('STOQ - Invalid or missing liquidRenderedAt timestamp, assuming fresh');
window._RestockRocketConfig.isLiquidCacheFresh = true;
} else {
const now = Math.floor(Date.now() / 1000); // Current time in seconds
const liquidCach<<<
&& 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);
});
}
});
}
// 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.S
hedSettings);
} else {
console.error('STOQ - failed to load settings:', error);
}
})
.catch(function(e) {
console.error(e)
})
}
function initializeScripts(settings) {
settings = applyTranslations(settings);
window._RestockRocketConfig.settings = settings;
console.debug(`STOQ - settings configured for ${window._RestockRocketConfig.pageType}`);
// 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);
})
if(window._RestockRocketConfig.pageType === 'collection' && (settings.show_button_on_collection || settings.preorder_collection_enabled)) {
createRestockRocketScript(window._RestockRocketCon
This site has limited support for your browser. We recommend switching to Edge, Chrome, Safari, or Firefox.led for ${window._RestockRocketConfig.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._RestockRocketConfig.pageType,
enabled: settings.enable_app,
settings: settings,
preorderEnabled: settings.preorder_enabled
}
});
console.debug('STOQ - dispatching app loaded event');
window.dispatchEvent(appLoadedEvent);
}
}
<
<
a class="product__media product__media--featured"
href="/collections/all
Seat Posts & Clamps
Shop All Second-Hand
Clothing<
Pedals
the frame up to 2.4”). A 10 speed one by drivetrain with a notable 11-36T gear range, short reach stem, butted 560mm riser bars, lock on grips and some of the lightest actuating hydraulic brakes available... a very serious piece of kit.\u003cbr\u003e\nASSEMBLY INSTRUCTIONS:\u003cbr\u003e\nYour bike will arrive carefully packaged and boxed with the rear wheel attached. The front wheel will need attaching using the axle supplied. The handlebar will be ziptied to the top tube, simply remove the bars and all packaging and attach to the stem. Add the saddle and adjust to the required height. Then simply add the pedals. You will be emailed an unboxing video with full instructions. Please retain your manual.\u003c\/p\u003e"};
window._RestockRocketConfig.variantsInventoryPolicy = {56393239921023 : "deny",};
window._RestockRocketConfig.variantsInventoryQuantity = {56393239921023 : parseInt("0"),};
window._RestockRocketConfig.variantsPreorderCount = {56393239921023 : parseInt(""),};
window._RestockRo
<a class="product__media product__media--featured"
href="/collections/all-products/products/hire-bike-packing-bundle"
title="HIRE - BIKE PACKING BUNDLE"
aria-label="HIRE - BIKE PACKING BUNDLE"
style="background-image: url(//projektride.co.uk/cdn/shop/files/Yourparagraphtext_600x.png?v=1747481130)">
65/assets/restockrocket-collection.js'
window._RestockRocketConfig.scriptHost = window._RestockRocketConfig.scriptUrlProduct.substring(0, window._RestockRocketConfig.scriptUrlProduct.lastIndexOf('/') + 1)
window._RestockRocketConfig.host = 'https://app.restockrocket.io'
const SETTINGS_CACHE_DURATION = 15 * 60 * 1000; // 15 minutes in milliseconds
const LIQUID_CACHE_MAX_AGE = 2 * 60 * 60; // 2 hours in seconds
// Calculate Liquid cache freshness once at initialization
const liquidRenderedAt = window._RestockRocketConfig.liquidRenderedAt;
// Validate timestamp and calculate cache age
if (!liquidRenderedAt || typeof liquidRenderedAt !== 'number' || isNaN(liquidRenderedAt)) {
console.debug('STOQ - Invalid or missing liquidRenderedAt timestamp, assuming fresh');
window._RestockRocketConfig.isLiquidCacheFresh = true;
} else {
const now = Math.floor(Date.now() / 1000); // Current time in seconds
const liquidCacheAge = now - liquidRenderedAt; // Age in seconds
// Handle clien
Maintenance<
span class="visually-hidden">HIRE - BIKE PACKING BUNDLE
<
>
<
Wheels
div class="product__media-hover-img product__media" style="background-image: url(//projektride.co.uk/cdn/shop/files/resize_width_1000_1296x_d1ffd242-63bc-4a9f-85e2-400f274532d7_600x.jpg?v=1747481423)">M – 23.98 kg/52.87 lb (with TLR sealant, no tubes)led for ${window._RestockRocketConfig.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._RestockRocketConfig.pageType,
enabled: settings.enable_app,
settings: settings,
preorderEnabled: settings.preorder_enabled
}
});
console.debug('STOQ - dispatching app loaded event');
window.dispatchEvent(appLoadedEvent);
}
}
Other
<
a class="product__media product__media--featured"
href="/collections/all-products/products/kryptolok-standard-u-lock-with-4-foot-kryptoflex-cable-hire"
title="Hire Kryptolok Standard U-Lock & 4 foot Kryptoflex cable"
aria-label="Hire Kryptolok Standard U-Lock & 4 foot Kryptoflex cable"
style="background-image: url(//projektride.co.uk/cdn/shop/files/Screenshot2022-03-09at20.04.46_560e2033-8232-4bd3-a423-3ce8c9f11849_600x.png?v=1691610428)">
Helmets
<
span class="visually-hidden">Hire Kryptolok Standard U-Lock & 4 foot Kryptoflex cableWe reserve the right to make changes to the product information contained on this site at any time without notice, including with respect to equipment, specifications, models, colours, materials and pricing. Due to supply chain issues, compatible parts may be substituted at any time without notice.Custom Builds
>
uro e-MTB made for your most epic adventures. Its robust carbon frame packs 160 mm of front and rear upgraded RockShox suspension and adjustable geometry you can tune to how and where you ride. It comes equipped with a Bosch CX Line motor that delivers serious torque for ripping up climbs and a huge 800 Wh RIB 2.0 removable integrated battery. It's topped off with all the bells and whistles you want – like carbon wheels and a wireless SRAM XX transmission.\u003c\/strong\u003e\u003c\/p\u003e\n\u003cp\u003e\u003cstrong\u003eIt's right for you if...\u003c\/strong\u003e\u003c\/p\u003e\n\u003cp\u003e\u003cbr\u003eYou want a big, power-packed e-bike that's built for massive adventure and doesn't skimp on choice parts. You need plenty of travel for rough and rowdy terrain, a powerful motor that crushes climbs and massive battery to keep you going on your longest rides yet. Upgrades matter, and you want SRAM's top wireless transmission and the added benefit of a RockShox suspension package.\u003c\/p\u003e\n\u003cp\UTO (ex Eovolt) Looking to purchase with a cycle to work scheme?
Click here to get in touch and get the ball rolling!
ve 108, 6-bolt, Boost148, 12 mm thru axle, 27.5\"\u003cbr\u003eSkewer rear Bontrager Switch thru-axle, removable lever\u003cbr\u003e*Tyre Size: S, M, L, XL\u003cbr\u003eBontrager Brevard RSL SE, Tubeless Ready, triple compound, aramid bead, 60 tpi, 27.5x2.50\"\u003cbr\u003eSize: M, L, XL\u003cbr\u003eBontrager Brevard RSL SE, Tubeless Ready, triple compound, aramid bead, 60 tpi, 29x2.50\"\u003cbr\u003eTyre part Bontrager TLR sealant, 180 ml\/6 oz\u003cbr\u003eRim strip Bontrager TLR\u003cbr\u003eMax tyre size Frame: 27.5x2.60\", Fork: See manufacturer\u003c\/p\u003e\n\u003cp\u003eE-system\u003cbr\u003eCharger Bosch standard 4A, 230V, smart system\u003cbr\u003eController Bosch System Controller BRC3100, smart system\u003cbr\u003eMotor Bosch Performance Line CX, 20 mph \/ 32 km\/h max assist (25 km\/h max assist in EU and APAC)\u003c\/p\u003e\n\u003cp\u003eDrivetrain\u003cbr\u003eRear derailleur SRAM XX Eagle AXS, T-Type\u003cbr\u003eCrank SRAM XX Eagle,165 mm l
Size: S, M, L, XL\u003cbr\u003eSRAM 6-bolt, 200 mm\u003cbr\u003eSize: S, M, L, XL\u003cbr\u003eSRAM HS2, 6-bolt, 220mm\u003cbr\u003eRotor size Max brake rotor sizes – Frame: 220 mm, Fork: see fork manufacturer\u003c\/p\u003e\n\u003cp\u003eAccessories\u003cbr\u003eMudguard Trek 27.5\" custom fender\u003c\/p\u003e\n\u003cp\u003eWeight\u003cbr\u003eWeight M - 24.03 kg \/ 52.98 lbs (with TLR sealant, no tubes)\u003cbr\u003eWeight limit This bike has a maximum total weight limit (combined weight of bicycle, rider and cargo) of 136 kg (300 lb).\u003c\/p\u003e\n\u003cp\u003e\u003cbr\u003eWe reserve the right to make changes to the product information contained on this site at any time without notice, including with respect to equipment, specifications, models, colours, materials and pricing. Due to supply chain issues, compatible parts may be substituted at any time without notice.\u003c\/p\u003e\n\u003cp\u003eBike and frame weights are based on pre-production painted frames at time of publicEarly Rider
ProjektRide Bike Shop Edinburghtranslation 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
<
UTO (ex Eovolt)
!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
&& 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);
});
}
});
}
// 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.SShop All Second-Hand52
Open search bar