window._RestockRocketConfig = window._RestockRocketConfig || {}
// Stoq is the current name of the app (RestockRocket is the legacy name).
// Expose _Stoq / _StoqConfig as live aliases of the same objects so both names
// work. Done here, before the JS bundles run, and the bundles only ever do
// `window._RestockRock
<
uuid>/-<
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
< 0) {
console.debug(`STOQ - Client clock appears ahead of server by ${Math.abs(Math.round(liquidCacheAge / 60))} minutes, assuming cache fresh`);
window._RestockRocketConfig.isLiquidCacheFresh = true;
} else if (liquidCacheAge Maintenance<= 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;
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 || '',
detected_variant_ids: _stoqDetectedVariantIds,
selected_variant_id: _stoqSele
ctedVariantId || '',
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);
}
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 n
ormalizedLocale = 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:', normalizedL
The Slash SE is a limited-edition hard-hitting enduro bike that's ready for airtime. Its carbon frame is painted with a completely unique Project One Earth and Air scheme that's one-of-a-kind from bike to bike. It comes ready to rip with an upgraded RockShox Ultimate suspension package with Flight Attendant, a wireless SRAM GX AXS transmission, a Rockshox Reverb AXS dropper post and carbon bars.
It's right for you if...
You want a one-of-a-kind enduro sled that can handle the rowdiest trails and packs serious upgrades – like a RockShox Flight Attendant fork and shock that reads the terrain and your riding input to anticipate the perfect suspension position, so you can ride faster, harder and longer.
The tech you get
An OCLV Mountain Carbon frame with a one-of-a-kind Project One Earth and Air paint scheme. Upgraded 160 mm RockShox Super Deluxe Ultimate Flight Attendant shock and 170 mm RockShox ZEB Ultimate fork with Flight Attendant, Debon Air spring and Charger 2.1 RCT3 AXS damper. Tubeless-Ready Bontrager Line Comp 29˝ wheels, a wireless SRAM GX AXS transmission, RockShox Reverb AXS dropper post, carbon bars and SRAM CODE Bronze 4-piston hydraulic brakes.
The final word
When you're ready to rip on a long-travel enduro rig that's spec'd to turn heads, reach for the Slash SE. This ride is more than just a rad paint scheme – it also delivers Rock Shox Flight Attendant for a ride that predicts your every move and dials itself in so you can just focus on slaying the trail.
Each Slash SE's paint scheme is one-of-a-kind, with elements that give a nod to staying planted through the rowdiest rock gardens and boosting big in the park
It's our most pocket-friendly ride equipped with Flight Attendant – a RockShox technology that uses wireless sensors in the fork, shock and crank to automatically adjust your suspension damping to the terrain
The SRAM's GX AXS transmission gives fully wireless shifting that stays clean and precise, even under load
The upgraded RockShox Reverb AXS dropper post gives you fully wireless dropper actuation
The RockShox ZEB fork's bigger 38 mm stanchions help you stay on your line through the chunky stuff, while the updated damper lets you dial in the feel
*Please note – spec applies to all sizes unless listed separately
Frameset Frame OCLV Mountain Carbon main frame and stays, internal storage, tapered head tube, Knock Block 2.0, Control Freak internal routing, Carbon Armour, shuttle guard, threaded BB, ISCG 05, 34.9 mm seat tube, magnesium rocker link, Mino Link, ABP, Boost148, 160 mm travel Frame OCLV Mountain Carbon main frame and stays, internal storage, tapered head tube, Knock Block 2.0, Control Freak internal routing, Carbon Armour, shuttle guard, threaded BB, ISCG 05, 34.9 mm seat tube, magnesium rocker link, Mino Link, ABP, Boost148, 160 mm travel Fork RockShox ZEB Ultimate, Flight Attendant, DebonAir spring, Charger 2.1 RCT3 AXS damper, 1.5'' tapered steerer, 44 mm offset, Boost110, 15 mm Maxle Stealth, 170 mm travel Shock RockShox Super Deluxe Ultimate Flight Attendant, 230 mm x 62.5 mm Max compatible fork travel 180mm (596mm axle-to-crown)
Wheels Wheel front Bontrager Line Comp 30, Tubeless Ready, 6-bolt, Boost110, 15 mm thru axle, 29" Wheel rear Bontrager Line Comp 30, Tubeless-Ready, Rapid Drive 54, 6-bolt, Boost148, 12 mm thru axle Skewer rear Bontrager Switch thru-axle, removable lever *Tyre Size: S , M , ML , L , XL Bontrager SE5 Team Issue, Tubeless Ready, Core Strength sidewalls, aramid bead, 120 tpi, 29x2.50" Size: S , M , ML , L , XL Bontrager SE6 Team Issue, Tubeless Ready, Core Strength sidewalls, aramid bead, 120 tpi, 29x2.50" Tyre part Bontrager TLR sealant, 180 ml/6 oz Rim strip Bontrager TLR Max tyre size Frame: 29x2.50", Fork: See manufacturer
Drivetrain *Shifter Size: S , M , ML , L , XL SRAM AXS POD Size: S , M , ML , L , XL SRAM AXS POD, paired with dropper Rear derailleur SRAM GX Eagle AXS, T-Type Crank SRAM GX Eagle, DUB MTB Wide, T-Type, 30T, 55 mm chain line, 165 mm length Bottom bracket SRAM DUB MTB Wide, 73 m, BSA threaded Cassette SRAM Eagle XS-1275, T-Type,10-52, 12-speed Chain SRAM GX Eagle, T-Type, 12-speed Max. chainring size 1x: 34T, min 28T
Components Saddle Bontrager Arvada Elite, stainless steel rails, 138 mm width *Seatpost Size: S RockShox Reverb AXS, 100 mm travel, wireless, 34.9 mm, 340 mm length Size: M , ML RockShox Reverb AXS, 150 mm travel, wireless, 34.9 mm, 440 mm length Size: L , XL RockShox Reverb AXS, 170 mm travel, wireless, 34.9 mm, 480 mm length Handlebar Bontrager Line Pro, OCLV Carbon, 35 mm, 27.5 mm rise, 780 mm width Grips Bontrager XR Trail Pro, alloy lock-on Stem Bontrager Line Pro, 35 mm, Blendr-compatible, 0-degree, 35 mm length Head set Knock Block 2.0 Integrated, 72-degree radius (includes infinite-radius chip), sealed cartridge bearing, 1-1/8'' top, 1.5'' bottom Brake SRAM CODE Bronze 4-piston hydraulic disc Brake rotor SRAM 6-bolt, 200 mm Rotor size Max brake rotor sizes - Frame: 220mm, Fork: see fork manufacturer
Accessories Bag Bontrager BITS Internal Frame Storage Bag
Weight Weight M - 15.53 kg / 34.24 lbs (with TLR sealant, no tubes) Weight limit This bike has a maximum total weight limit (combined weight of bicycle, rider and cargo) of 136 kg (300 lb). We 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.
Bike and frame weights are based on pre-production painted frames at time of publication. Weights may vary in final production.
Frequently Asked Questions
Please get in touch with a member of the team either by phone (01313745324) or email ([email protected]) where on of the team will be more than happy to help.
ProjektRide Bike Shop Edinburgh
If the item is showing in stock, we aim to post the product within 24 hours. Please allow 5 working days to receive the item.
Postage is free on orders over £50. Orders under £50, our postage charge is £3.99.
We also have a physical store, if you are local please pop in -