to module/shell asset URLs in rendered HTML. */
export function versionAssetUrls(html: string): string {
return html.replace(
/(["'])(\/(?:modules\/[^"'?]+\.(?:js|css)|shell\.js|shell\.css|theme\.css))(?:\?v=[^"']*)?(\1)/g,
(_, q, path, qEnd) => {
const hash = moduleHashes[path];
return hash ? `${q}${path}?v=${hash}${qEnd}` : `${q}${path}${qEnd}`;
}
);
}
/** Extract enabledModules and encryption status from a loaded space. */
export function getSpaceShellMeta(spaceSlug: string): { enabledModules: string[] | null; spaceEncrypted: boolean } {
const data = getDocumentData(spaceSlug);
return {
enabledModules: data?.meta?.enabledModules ?? null,
spaceEncrypted: !!data?.meta?.encrypted,
};
}
/**
* Render a lightweight JSON fragment for tab-cache.
* Returns only the body HTML, title, scripts, and styles — no shell chrome.
* Used by TabCache's ?fragment=1 requests to avoid re-rendering the full 2000-line shell.
*/
export function renderFragment(opts: {
title: string;
body: string;
scripts?: string;
styles?: string;
}): string {
// Parse script srcs from the scripts string
const scriptSrcs: string[] = [];
const scriptRe = /src="([^"]+)"/g;
let m: RegExpExecArray | null;
if (opts.scripts) {
while ((m = scriptRe.exec(opts.scripts)) !== null) {
scriptSrcs.push(m[1]);
}
}
// Parse stylesheet hrefs from the styles string
const styleSrcs: string[] = [];
const styleRe = /href="([^"]+)"/g;
if (opts.styles) {
while ((m = styleRe.exec(opts.styles)) !== null) {
styleSrcs.push(m[1]);
}
}
// Extract inline
${styles}
${head}
Install rSpace app for the best experience
New version available
${renderModuleSubNav(moduleId, spaceSlug, visibleModules, opts.isSubdomain ?? IS_PRODUCTION)}
${opts.tabs ? renderTabBar(opts.tabs, opts.activeTab, opts.tabBasePath || ((opts.isSubdomain ?? IS_PRODUCTION) ? `/${escapeAttr(moduleId)}` : `/${escapeAttr(spaceSlug)}/${escapeAttr(moduleId)}`)) : ''}
${body}
${renderWelcomeOverlay()}
${scripts}