Skip to content
Scottish Bikepacking Guide If you're researching scottish bikepacking guide, ProjektRide is ideally positioned to help. Based in Edinburgh, we specialise in premium bike hire for riders exploring Scotland's roads, gravel tracks, bikepacking routes and touring...
field.value;
if (!value) { throw new Error('Storefront API returned no ' + key + ' metafield value'); }
return JSON.parse(value);
});
}
function fetchStorefrontSettings() {
const query = 'query StoqSettings($namespace: String!) { shop { settings: metafield(namespace: $namespace, key: "settings") { value } translations: metafield(namespace: $namespace, key: "settings_translations") { value } } }';
return storefrontGraphql(query, { namespace: window._RestockRocketConfig.metafieldNamespace })
.then(function(data) {
const settings = JSON.parse(data.shop.settings.value);
if (!settings.updated_at) { throw new Error('settings metafield is not a settings payload'); }
if (settings.single_locale_translations_inline) {
settings.translations = data.shop.translations && JSON.parse(data.shop.translations.value);
}
if (settings.multi_language_enabled && !settings.translations) { throw new Error('settings metafield carries no translations'); }
return
settings;
});
}
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': 'skip'
};
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;
}
const storefrontRead = window._RestockRocketConfig.readFlags?.enable_storefront_settings_read === true
? Promise.race([
fetchStorefrontSettings(),
new Promi
se(function(_, reject) { setTimeout(function() { reject(new Error('timed out')); }, 1500); })
]).catch(function(error) {
console.debug('STOQ - Storefront settings read failed, using setting.json:', error.message);
})
: Promise.resolve();
storefrontRead
.then(function(settings) {
return settings || 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 (cachedSettings) {
console.debug('STOQ - using expired cached settings as fallback');
initializeScripts(cachedSettings);
} else {
console.error('STOQ - 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) {
console.error('STOQ - apply failed for ' + endpoint + ':', applyError);
throw applyError;
}
})
.catch(function(error) {
console.debug(`STOQ - using cached ${endpoint}:`, error.message);
});
}
function refreshShopConfig(source) {
const cfg = window._RestockRocketConfig;
const viaEmbed = function() { return fetchEmbedConfig(source.endpoint, source.apply); };
const flagOn = !!cfg.readFlags && cfg.readFlags[source.flag] === true;
if (!flagOn || source.embedOnly === true) { return viaEmbed(); }
return fetchStorefrontShopMetafield(source.metafieldKey)
.then(function(value) {
if (!source.isValid(value)) { throw new Error(source.metafieldKey + ' metafield is not a valid ' + source.endpoint + ' payload'); }
source.apply(value);
console.debug('STOQ - refreshed ' + source.endpoint + ' from the Storefront API');
})
.catch(function(error) {
console.debug('STOQ - Storefront ' + source.endpoint + ' read failed, using embed:', error.message);
return viaEmbed();
});
}
function refreshIntegrations() {
const cfg = window._RestockRocketConfig;
return refreshShopConfig({
endpoint: 'integrations',
metafieldKey: 'integrations',
flag: 'enable_storefront_integrations_read',
isValid: function(value) { return Array.isArray(value); },
apply: function(dat
a) {
cfg.integrations = data;
}
});
}
function refreshSellingPlans(embedOnly) {
const cfg = window._RestockRocketConfig;
return refreshShopConfig({
embedOnly: embedOnly === true,
endpoint: 'selling_plans',
metafieldKey: 'cachedSellingPlans',
flag: 'enable_storefront_selling_plans_read',
isValid: function(value) { return !!value && Array.isArray(value.plans); },
apply: function(data) {
cfg.sellingPlans = data.plans;
cfg.disabledSellingPlanIds = data.disabled_plan_ids || [];
if (data && data.read_flags && typeof data.read_flags === 'object' && !Array.isArray(data.read_flags)) {
cfg.readFlags = data.read_flags;
}
}
});
}
function initializeScripts(settings) {
settings = applyTranslations(settings);
window._RestockRocketConfig.settings = settings;
console.debug(`STOQ - settings configured for ${window._RestockRocketConfig.pageType}`);
const forceEmbedSellingPlans = settings.fo