@symbo.ls/utils 3.14.779 → 3.14.781

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";var S=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var T=(n,r)=>{for(var t in r)S(n,t,{get:r[t],enumerable:!0})},x=(n,r,t,e)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of E(r))!W.call(n,s)&&s!==t&&S(n,s,{get:()=>r[s],enumerable:!(e=O(r,s))||e.enumerable});return n};var D=n=>x(S({},"__esModule",{value:!0}),n);var H={};T(H,{generateHeadArrayTags:()=>L,generateMetaTags:()=>_,getPageMetadata:()=>C,hashContent:()=>b});module.exports=D(H);var A=require("./types.js"),w=require("./function.js");const a=n=>{if(n==null)return"";const r={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return n.toString().replace(/[&<>"']/g,t=>r[t])},F=n=>Object.entries(n||{}).filter(([r,t])=>t!==void 0).map(([r,t])=>`${r}="${a(t)}"`).join(" "),b=n=>{let r=5381;const t=String(n);for(let e=0;e<t.length;e++)r=(r*33^t.charCodeAt(e))>>>0;return r.toString(36)},R=new Set(["jsonLd","styles","scripts"]),L=n=>{const r=[];if(Array.isArray(n.jsonLd))for(const t of n.jsonLd){if(t==null)continue;const e=typeof t=="string"?t:JSON.stringify(t),s=String(e).replace(/<\/script/gi,"<\\/script");r.push(`<script type="application/ld+json" data-smbls-jsonld="${b(e)}">${s}<\/script>`)}if(Array.isArray(n.styles))for(const t of n.styles){if(t==null||!String(t).trim())continue;const e=String(t).replace(/<\/style/gi,"<\\/style");r.push(`<style data-smbls-style="${b(e)}">${e}</style>`)}if(Array.isArray(n.scripts))for(const t of n.scripts){if(!t)continue;const e=typeof t=="string",s=e?t:t.src;if(!s&&!t.body)continue;const o=[];s&&o.push(`src="${a(s)}"`),e||(t.type&&o.push(`type="${a(t.type)}"`),t.async&&o.push("async"),t.defer&&o.push("defer"),t.integrity&&o.push(`integrity="${a(t.integrity)}"`),t.crossorigin&&o.push(`crossorigin="${a(t.crossorigin)}"`),t.referrerpolicy&&o.push(`referrerpolicy="${a(t.referrerpolicy)}"`),t.nomodule&&o.push("nomodule"));const f=` data-smbls-script="${a(s||b(t.body||""))}"`;if(!e&&t.body){const h=String(t.body).replace(/<\/script/gi,"<\\/script");r.push(`<script ${o.join(" ")}${f}>${h}<\/script>`)}else r.push(`<script ${o.join(" ")}${f}><\/script>`)}return r},_=(n,r)=>{r||(n={...n,robots:"noindex"});const t=Object.entries(n).reduce((e,[s,o])=>{if(!o&&o!==0&&o!==!1||R.has(s))return e;if(s==="title")return e.push(`<title>${a(o)}</title>`),e;if(s==="canonical")return e.push(`<link rel="canonical" href="${a(o)}">`),e;if(s==="manifest")return e.push(`<link rel="manifest" href="${a(o)}">`),e;if(s==="favicon"||s==="favicons"||s==="icon"||s==="icons")return(Array.isArray(o)?o:[o]).forEach(p=>{if(typeof p=="string")e.push(`<link rel="icon" href="${a(p)}">`);else if(typeof p=="object"){const u=F(p);/rel=/.test(u)?e.push(`<link ${u}>`):e.push(`<link rel="icon" ${u}>`)}}),e;if(s==="alternate")return(Array.isArray(o)?o:[o]).forEach(p=>{if(typeof p=="object"){const u=Object.entries(p).filter(([i,g])=>g!==void 0).map(([i,g])=>`${i}="${a(g)}"`).join(" ");e.push(`<link rel="alternate" ${u}>`)}}),e;const f=(l,p,u="name")=>{if(typeof p=="string"||typeof p=="number"||typeof p=="boolean")e.push(`<meta ${u}="${a(l)}" content="${a(p)}">`);else if(Array.isArray(p))p.forEach(i=>{if(typeof i=="string"||typeof i=="number"||typeof i=="boolean")e.push(`<meta ${u}="${a(l)}" content="${a(i)}">`);else if(typeof i=="object"){const g=Object.entries(i).filter(([d,c])=>c!==void 0).map(([d,c])=>`${d}="${a(c)}"`).join(" ");e.push(`<meta ${g}>`)}});else if(typeof p=="object"){const i=Object.entries(p).filter(([g,d])=>d!==void 0).map(([g,d])=>`${g}="${a(d)}"`).join(" ");e.push(`<meta ${i}>`)}};if(s.startsWith("http-equiv:")){const l=s.replace("http-equiv:","");return f(l,o,"http-equiv"),e}if(s.startsWith("itemprop:")){const l=s.replace("itemprop:","");return f(l,o,"itemprop"),e}const y=["og:","twitter:","fb:","article:","profile:","book:","business:","music:","product:","video:","DC:","DCTERMS:"].find(l=>s.startsWith(l));if(y){const l=s.replace(y,"");return f(`${y.replace(":","")}:${l}`,o,y==="twitter:"||y==="DC:"||y==="DCTERMS:"?"name":"property"),e}if(s.startsWith("apple:")||s.startsWith("msapplication:")){const l=s.startsWith("apple:")?"apple-":"msapplication-",p=s.replace(/^apple:|^msapplication:/,"");return f(`${l}${p}`,o,"name"),e}return f(s,o),e},['<meta charset="UTF-8">','<meta name="viewport" content="width=device-width, initial-scale=1">']);return t.push(...L(n)),t.join(`
2
- `)},q=n=>typeof n=="string"&&n.length>0&&!n.startsWith("/")&&!n.startsWith("http");function K(n,r){if(!r||typeof r!="object")return n;const t=s=>{if(!q(s))return s;const o=r[s];return o?.src?o.src:s},e={...n};for(const[s,o]of Object.entries(e))typeof o=="string"?e[s]=t(o):Array.isArray(o)&&(e[s]=o.map(f=>typeof f=="string"?t(f):f));return e}function m(n,r){if(!n||!r)return;const t=r.split(".");let e=n;for(const s of t){if(e==null||typeof e!="object")return;e=e[s]}return e}function P(n,r,t){const s=(r.config||r.settings||{}).polyglot||r.polyglot,o=t?.lang||s?.defaultLang||"en",h=(s?.translations||{})[o]||{},y=t?.state||{},l={...n};for(const[p,u]of Object.entries(l))typeof u!="string"||!u.includes("{{")||(l[p]=u.replace(/\{\{\s*([^|{}]+?)\s*(?:\|\s*(\w+)\s*)?\}\}/g,(i,g,d)=>{const c=g.trim();if(d==="polyglot")return h[c]??m(h,c)??i;if(d==="getLocalStateLang")return m(y,c+o)??i;const $=m(y,c);return $!==void 0?$:h[c]??m(h,c)??i}));return l}function M(n){if(!(0,A.isObject)(n))return{};const r={...n};for(const[t,e]of Object.entries(r))if(typeof e=="function"){const s=e.toString(),o=s.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(o){r[t]=`{{ ${o[1]} | getLocalStateLang }}`;continue}const f=s.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(f){r[t]=`{{ ${f[1]} | polyglot }}`;continue}const h=s.match(/s\.(\w+(?:\.\w+)+)/);if(h){r[t]=`{{ ${h[1]} }}`;continue}delete r[t]}else if(typeof e=="string"){const s=e.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(s){r[t]=`{{ ${s[1]} | getLocalStateLang }}`;continue}const o=e.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(o){r[t]=`{{ ${o[1]} | polyglot }}`;continue}if(e.includes("=>")&&e.includes("s.")){const f=e.match(/s\.(\w+(?:\.\w+)+)/);if(f){r[t]=`{{ ${f[1]} }}`;continue}}(0,w.isStringFunction)(e)&&delete r[t]}return r}function C(n,r,t,{isProduction:e=!1,channel:s="production"}={}){const o=n.pages?.[r],f=(0,A.isObject)(o?.state)&&o?.state,h=o?.metadata||o?.helmet||f||{},y=M(h),l=new Set(Object.keys(y)),p=n.app?.metadata||{},u=M(p);let i={};if(n.integrations?.seo?i={...n.integrations.seo,...u,...y}:Object.keys(u).length?i={...u,...y}:i={...y},!i.title){const c=n.name||n.key;c?e?i.title=c:s==="development"?i.title=`${c} / dev:symbo.ls`:s==="staging"?i.title=`${c} / staging:symbo.ls`:i.title=`${c} / symbo.ls`:i.title="Symbols demo"}i=P(i,n,t),i.title&&(l.has("title")||!i["og:title"])&&(l.has("og:title")||(i["og:title"]=i.title)),i.description&&(l.has("description")||!i["og:description"])&&(l.has("og:description")||(i["og:description"]=i.description)),i.title&&!i["twitter:title"]&&(i["twitter:title"]=i.title),i.description&&!i["twitter:description"]&&(i["twitter:description"]=i.description);const g=t?.actualPathname||r;if(i["og:url"]||i.url){const c=(i["og:url"]||i.url||"").replace(/\/$/,"");if(c&&g&&g!=="/"){const $=g.startsWith("/")?g:"/"+g;i["og:url"]=c+$}}i=K(i,n.files);const d=n.name||n.app?.metadata?.title||n.app?.name||"";for(const[c,$]of Object.entries(i))if(typeof $=="string"&&$.includes("{{")){const j=$.replace(/\{\{[^}]*\}\}/g,"").trim();j?i[c]=j:c==="title"?i[c]=d:delete i[c]}return i}
1
+ "use strict";var j=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var D=(e,s)=>{for(var t in s)j(e,t,{get:s[t],enumerable:!0})},P=(e,s,t,n)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of T(s))!F.call(e,r)&&r!==t&&j(e,r,{get:()=>s[r],enumerable:!(n=x(s,r))||n.enumerable});return e};var R=e=>P(j({},"__esModule",{value:!0}),e);var Y={};D(Y,{fileEntryUrl:()=>E,generateHeadArrayTags:()=>L,generateMetaTags:()=>q,getPageMetadata:()=>N,hashContent:()=>b,resolveFileReferences:()=>W});module.exports=R(Y);var w=require("./types.js"),M=require("./function.js");const g=e=>{if(e==null)return"";const s={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return e.toString().replace(/[&<>"']/g,t=>s[t])},U=e=>Object.entries(e||{}).filter(([s,t])=>t!==void 0).map(([s,t])=>`${s}="${g(t)}"`).join(" "),b=e=>{let s=5381;const t=String(e);for(let n=0;n<t.length;n++)s=(s*33^t.charCodeAt(n))>>>0;return s.toString(36)},_=new Set(["jsonLd","styles","scripts"]),L=e=>{const s=[];if(Array.isArray(e.jsonLd))for(const t of e.jsonLd){if(t==null)continue;const n=typeof t=="string"?t:JSON.stringify(t),r=String(n).replace(/<\/script/gi,"<\\/script");s.push(`<script type="application/ld+json" data-smbls-jsonld="${b(n)}">${r}<\/script>`)}if(Array.isArray(e.styles))for(const t of e.styles){if(t==null||!String(t).trim())continue;const n=String(t).replace(/<\/style/gi,"<\\/style");s.push(`<style data-smbls-style="${b(n)}">${n}</style>`)}if(Array.isArray(e.scripts))for(const t of e.scripts){if(!t)continue;const n=typeof t=="string",r=n?t:t.src;if(!r&&!t.body)continue;const o=[];r&&o.push(`src="${g(r)}"`),n||(t.type&&o.push(`type="${g(t.type)}"`),t.async&&o.push("async"),t.defer&&o.push("defer"),t.integrity&&o.push(`integrity="${g(t.integrity)}"`),t.crossorigin&&o.push(`crossorigin="${g(t.crossorigin)}"`),t.referrerpolicy&&o.push(`referrerpolicy="${g(t.referrerpolicy)}"`),t.nomodule&&o.push("nomodule"));const l=` data-smbls-script="${g(r||b(t.body||""))}"`;if(!n&&t.body){const h=String(t.body).replace(/<\/script/gi,"<\\/script");s.push(`<script ${o.join(" ")}${l}>${h}<\/script>`)}else s.push(`<script ${o.join(" ")}${l}><\/script>`)}return s},q=(e,s)=>{s||(e={...e,robots:"noindex"});const t=Object.entries(e).reduce((n,[r,o])=>{if(!o&&o!==0&&o!==!1||_.has(r))return n;if(r==="title")return n.push(`<title>${g(o)}</title>`),n;if(r==="canonical")return n.push(`<link rel="canonical" href="${g(o)}">`),n;if(r==="manifest")return n.push(`<link rel="manifest" href="${g(o)}">`),n;if(r==="favicon"||r==="favicons"||r==="icon"||r==="icons")return(Array.isArray(o)?o:[o]).forEach(c=>{if(typeof c=="string")n.push(`<link rel="icon" href="${g(c)}">`);else if(typeof c=="object"){const u=U(c);/rel=/.test(u)?n.push(`<link ${u}>`):n.push(`<link rel="icon" ${u}>`)}}),n;if(r==="alternate")return(Array.isArray(o)?o:[o]).forEach(c=>{if(typeof c=="object"){const u=Object.entries(c).filter(([i,p])=>p!==void 0).map(([i,p])=>`${i}="${g(p)}"`).join(" ");n.push(`<link rel="alternate" ${u}>`)}}),n;const l=(f,c,u="name")=>{if(typeof c=="string"||typeof c=="number"||typeof c=="boolean")n.push(`<meta ${u}="${g(f)}" content="${g(c)}">`);else if(Array.isArray(c))c.forEach(i=>{if(typeof i=="string"||typeof i=="number"||typeof i=="boolean")n.push(`<meta ${u}="${g(f)}" content="${g(i)}">`);else if(typeof i=="object"){const p=Object.entries(i).filter(([m,a])=>a!==void 0).map(([m,a])=>`${m}="${g(a)}"`).join(" ");n.push(`<meta ${p}>`)}});else if(typeof c=="object"){const i=Object.entries(c).filter(([p,m])=>m!==void 0).map(([p,m])=>`${p}="${g(m)}"`).join(" ");n.push(`<meta ${i}>`)}};if(r.startsWith("http-equiv:")){const f=r.replace("http-equiv:","");return l(f,o,"http-equiv"),n}if(r.startsWith("itemprop:")){const f=r.replace("itemprop:","");return l(f,o,"itemprop"),n}const y=["og:","twitter:","fb:","article:","profile:","book:","business:","music:","product:","video:","DC:","DCTERMS:"].find(f=>r.startsWith(f));if(y){const f=r.replace(y,"");return l(`${y.replace(":","")}:${f}`,o,y==="twitter:"||y==="DC:"||y==="DCTERMS:"?"name":"property"),n}if(r.startsWith("apple:")||r.startsWith("msapplication:")){const f=r.startsWith("apple:")?"apple-":"msapplication-",c=r.replace(/^apple:|^msapplication:/,"");return l(`${f}${c}`,o,"name"),n}return l(r,o),n},['<meta charset="UTF-8">','<meta name="viewport" content="width=device-width, initial-scale=1">']);return t.push(...L(e)),t.join(`
2
+ `)},K=e=>typeof e=="string"&&e.length>0&&!e.startsWith("/")&&!e.startsWith("http"),S=e=>typeof e=="string"&&e.length>0,E=e=>{if(!e||typeof e!="object")return null;if(S(e.src))return e.src;const s=e.content;return!s||typeof s!="object"?null:S(s.src)?s.src:S(s.storageUrl)?s.storageUrl:null};function W(e,s){if(!s||typeof s!="object")return e;const t=r=>!K(r)||!Object.prototype.hasOwnProperty.call(s,r)?r:E(s[r])||r,n={...e};for(const[r,o]of Object.entries(n))typeof o=="string"?n[r]=t(o):Array.isArray(o)&&(n[r]=o.map(l=>typeof l=="string"?t(l):l));return n}function A(e,s){if(!e||!s)return;const t=s.split(".");let n=e;for(const r of t){if(n==null||typeof n!="object")return;n=n[r]}return n}function C(e,s){const t=A(e,s);if(typeof t=="number")return Number.isFinite(t)?t:void 0;if(typeof t=="string"&&!(0,M.isStringFunction)(t))return t}function H(e,s,t){const r=(s.config||s.settings||{}).polyglot||s.polyglot,o=t?.lang||r?.defaultLang||"en",h=(r?.translations||{})[o]||{},y=[t?.state,s.state].filter(u=>u&&typeof u=="object"),f=u=>{for(const i of y){const p=C(i,u);if(p!==void 0)return p}},c={...e};for(const[u,i]of Object.entries(c))typeof i!="string"||!i.includes("{{")||(c[u]=i.replace(/\{\{\s*([^|{}]+?)\s*(?:\|\s*(\w+)\s*)?\}\}/g,(p,m,a)=>{const d=m.trim();if(a==="polyglot")return h[d]??A(h,d)??p;if(a==="getLocalStateLang")return f(d+o)??p;const $=f(d);return $!==void 0?$:h[d]??A(h,d)??p}));return c}function O(e){if(!(0,w.isObject)(e))return{};const s={...e};for(const[t,n]of Object.entries(s))if(typeof n=="function"){const r=n.toString(),o=r.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(o){s[t]=`{{ ${o[1]} | getLocalStateLang }}`;continue}const l=r.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(l){s[t]=`{{ ${l[1]} | polyglot }}`;continue}const h=r.match(/s\.(\w+(?:\.\w+)+)/);if(h){s[t]=`{{ ${h[1]} }}`;continue}delete s[t]}else if(typeof n=="string"){const r=n.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(r){s[t]=`{{ ${r[1]} | getLocalStateLang }}`;continue}const o=n.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(o){s[t]=`{{ ${o[1]} | polyglot }}`;continue}if(n.includes("=>")&&n.includes("s.")){const l=n.match(/s\.(\w+(?:\.\w+)+)/);if(l){s[t]=`{{ ${l[1]} }}`;continue}}(0,M.isStringFunction)(n)&&delete s[t]}return s}function N(e,s,t,{isProduction:n=!1,channel:r="production"}={}){const o=e.pages?.[s],l=(0,w.isObject)(o?.state)&&o?.state,h=o?.metadata||o?.helmet||l||{},y=O(h),f=new Set(Object.keys(y)),c=e.app?.metadata||{},u=O(c);let i={};if(e.integrations?.seo?i={...e.integrations.seo,...u,...y}:Object.keys(u).length?i={...u,...y}:i={...y},!i.title){const a=e.name||e.key;a?n?i.title=a:r==="development"?i.title=`${a} / dev:symbo.ls`:r==="staging"?i.title=`${a} / staging:symbo.ls`:i.title=`${a} / symbo.ls`:i.title="Symbols demo"}i=H(i,e,t),i.title&&(f.has("title")||!i["og:title"])&&(f.has("og:title")||(i["og:title"]=i.title)),i.description&&(f.has("description")||!i["og:description"])&&(f.has("og:description")||(i["og:description"]=i.description)),i.title&&!i["twitter:title"]&&(i["twitter:title"]=i.title),i.description&&!i["twitter:description"]&&(i["twitter:description"]=i.description);const p=t?.actualPathname||s;if(i["og:url"]||i.url){const a=(i["og:url"]||i.url||"").replace(/\/$/,"");if(a&&p&&p!=="/"){const d=p.startsWith("/")?p:"/"+p;i["og:url"]=a+d}}i=W(i,e.files);const m=e.name||e.app?.metadata?.title||e.app?.name||"";for(const[a,d]of Object.entries(i))if(typeof d=="string"&&d.includes("{{")){const $=d.replace(/\{\{[^}]*\}\}/g,"").trim();$?i[a]=$:a==="title"?i[a]=m:delete i[a]}return i}
@@ -1 +1 @@
1
- "use strict";var h=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var P=(n,t)=>{for(var o in t)h(n,o,{get:t[o],enumerable:!0})},M=(n,t,o,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of F(t))!U.call(n,s)&&s!==o&&h(n,s,{get:()=>t[s],enumerable:!(e=E(t,s))||e.enumerable});return n};var D=n=>M(h({},"__esModule",{value:!0}),n);var nn={};P(nn,{__resetBuiltinMethodWarnings:()=>Y,deepDefaults:()=>p,fetchLibraryData:()=>j,isWrappedLibrary:()=>w,mergeSharedLibraries:()=>Q,normalizeIgnoreList:()=>y,normalizeLibraryKey:()=>u,resolveSharedLibraries:()=>Z,sharedLibrary:()=>K});module.exports=D(nn);var l=require("./types.js"),f=require("./keys.js"),I=require("./env.js");const k="system",T="https://smbls-kv.nika-980.workers.dev",C="https://api.symbols.app";function u(n){const t=String(n||"").trim();if(!t)return{owner:k,key:"",full:""};let o=null,e=t;if(t.includes("/")){const r=t.indexOf("/");o=t.slice(0,r),e=t.slice(r+1)}e=e.replace(/\.symbo\.ls$/iu,""),o||(o=k);const s=e?`${o}/${e}`:"";return{owner:o,key:e,full:s}}const p=(n,t,o,e)=>{for(const s in t){const r=e?`${e}/${s}`:s;o&&o.has(r)||(s in n?(0,l.isObject)(n[s])&&(0,l.isObject)(t[s])&&p(n[s],t[s],o,r):n[s]=t[s])}},$=(n,t,o)=>{if(!(0,l.isObject)(n)||!t.size)return n;const e=`${o}/`;let s=!1;for(const a of t)if(a.startsWith(e)){s=!0;break}if(!s)return n;const r={};for(const a in n){if(!Object.prototype.hasOwnProperty.call(n,a))continue;const i=`${o}/${a}`;t.has(i)||(r[a]=$(n[a],t,i))}return r},N=new Set,G=new Set(["components","pages","functions","snippets","methods"]),L=(n,t)=>t===""&&G.has(n),A=["fontFamily","fontfamily","font_family","FONT_FAMILY"],W=n=>{const t=new Map;if(!(0,l.isObject)(n))return t;for(const o of A){const e=n[o];if((0,l.isObject)(e))for(const s in e)!(0,l.isObject)(e[s])||!e[s].isDefault||(t.has(o)||t.set(o,new Set),t.get(o).add(s))}return t},z=(n,t)=>{for(const o of A){const e=n[o];if(!(0,l.isObject)(e))continue;const s=t.get(o);let r=null;for(const a in e){const i=e[a];if(!(0,l.isObject)(i)||!i.isDefault||s&&s.has(a))continue;const c={...i};delete c.isDefault,r||(r={...e}),r[a]=c}r&&(n[o]=r)}},J=n=>n.replace(/\.js$/iu,""),y=n=>{const t=new Set;if(!Array.isArray(n))return t;for(const o of n){if(!(0,l.isString)(o))continue;const e=o.split("/").map(s=>J(s.trim())).filter(Boolean).join("/");e&&t.add(e)}return t},K=(n,t={})=>({library:n,ignoreList:Array.isArray(t.ignoreList)?t.ignoreList:[]}),w=n=>(0,l.isObject)(n)&&Array.isArray(n.ignoreList)&&("library"in n||"key"in n||"name"in n),S=n=>n.library!==void 0?n.library:n.key??n.name,m=new Set,Y=()=>{m.clear()},x=(n,t)=>{const o=t.filter(e=>!m.has(e));if(o.length){for(const e of o)m.add(e);(0,I.isLoudDevRuntime)()&&console.warn(`[smbls] shared library "${n}" ships ${o.map(e=>`methods.${e}`).join(", ")} \u2014 named like a built-in element method. Refused: the built-in wins; a library cannot replace an element method on the consuming app. If the app wants this version, declare it in the app's OWN methods.`)}},V=(n,t,o)=>{let e=null;for(const s in n)if((0,f.isProtectedElementMethod)(s)&&(t.has(`methods/${s}`)||o.push(s),!e)){e={};for(const r in n)(0,f.isProtectedElementMethod)(r)||(e[r]=n[r])}return e||n},q=(n,t,o,e="library")=>{const s=y(t.sharedLibIgnore);t.sharePages===!1&&s.add("pages");const r=s.size?new Set([...o,...s]):o,a=[];for(const i in t)if(Object.prototype.hasOwnProperty.call(t,i)&&!(i==="sharePages"||i==="sharedLibIgnore")&&i!=="app"&&!r.has(i)){if((0,l.isObject)(t[i])&&(0,l.isObject)(n[i])){if(i==="designSystem")p(n[i],t[i],r,i);else for(const c in t[i])if(!r.has(`${i}/${c}`)){if(i==="methods"&&(0,f.isProtectedElementMethod)(c)){c in n[i]||a.push(c);continue}c in n[i]?L(i,n[i][c])&&!L(i,t[i][c])&&(n[i][c]=t[i][c]):n[i][c]=t[i][c]}}else if(!(i in n)){const c=t[i],d=i==="methods"&&c&&typeof c=="object"?V(c,r,a):c;n[i]=$(d,r,i)}}a.length&&x(e,a)},H=(n,t,o)=>{if(n!==t){const e=S(n);if((0,l.isString)(e)&&e)return e;if(n.key||n.name)return n.key||n.name}return t&&(t.key||t.name)||`sharedLibraries[${o}]`},Q=(n,t)=>{if(!t||!t.length)return;const o=W(n.designSystem);for(let e=0;e<t.length;e++){const s=t[e];let r=s,a=N;w(r)&&(a=y(r.ignoreList),r=r.library),(0,l.isObject)(r)&&q(n,r,a,H(s,r,e))}o.size&&z(n.designSystem,o)};async function j(n,t={}){if((t.provider||"kv")==="api")return _(n,t);const e=await X(n,t);return e||_(n,t)}async function X(n,t={}){const o=t.kvBaseUrl||T,e=t.env||"production",s=`${o}/kv/${encodeURIComponent(n)}?env=${e}`;try{const r=await fetch(s,{method:"GET"});return r.ok&&(await r.json())?.value||null}catch{return null}}async function _(n,t={}){const o=t.apiBaseUrl||C,{key:e}=u(n);try{const s=`${o}/core/projects/libraries/available?search=${encodeURIComponent(e)}&limit=10`,r=await fetch(s,{method:"GET"});if(!r.ok)return null;const a=await r.json(),c=(a?.items||a?.data||(Array.isArray(a)?a:[])).find(O=>{const{key:B}=u(O?.key);return B.toLowerCase()===e.toLowerCase()});if(!c?.id&&!c?._id)return null;const d=c.id||c._id,R=`${o}/core/projects/${encodeURIComponent(d)}/data?branch=main`,b=await fetch(R,{method:"GET"});if(!b.ok)return null;const g=await b.json();return g?.data||g||null}catch{return null}}async function v(n,t={}){if((0,l.isObject)(n))return n;if((0,l.isString)(n)){const{full:o}=u(n);if(!o)return null;try{const e=await j(o,t);return e||console.warn(`[smbls] Shared library "${o}" not found`),e}catch(e){return console.warn(`[smbls] Failed to fetch shared library "${o}":`,e.message),null}}return null}async function Z(n,t={}){return!n||!n.length?[]:(await Promise.all(n.map(async e=>{if(w(e)){const s=await v(S(e),t);return s?{library:s,ignoreList:e.ignoreList}:null}return v(e,t)}))).filter(Boolean)}
1
+ "use strict";var d=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var T=(n,e)=>{for(var s in e)d(n,s,{get:e[s],enumerable:!0})},z=(n,e,s,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of C(e))!D.call(n,o)&&o!==s&&d(n,o,{get:()=>e[o],enumerable:!(t=M(e,o))||t.enumerable});return n};var N=n=>z(d({},"__esModule",{value:!0}),n);var cn={};T(cn,{__resetBuiltinMethodWarnings:()=>q,deepDefaults:()=>m,fetchLibraryData:()=>O,isWrappedLibrary:()=>k,mergeSharedLibraries:()=>sn,mergeSharedLibraryDesignSystems:()=>rn,normalizeIgnoreList:()=>y,normalizeLibraryKey:()=>f,resolveSharedLibraries:()=>an,sharedLibrary:()=>V});module.exports=N(cn);var c=require("./types.js"),u=require("./keys.js"),B=require("./env.js");const h="system",G="https://smbls-kv.nika-980.workers.dev",K="https://api.symbols.app";function f(n){const e=String(n||"").trim();if(!e)return{owner:h,key:"",full:""};let s=null,t=e;if(e.includes("/")){const i=e.indexOf("/");s=e.slice(0,i),t=e.slice(i+1)}t=t.replace(/\.symbo\.ls$/iu,""),s||(s=h);const o=t?`${s}/${t}`:"";return{owner:s,key:t,full:o}}const m=(n,e,s,t)=>{for(const o in e){const i=t?`${t}/${o}`:o;s&&s.has(i)||(o in n?(0,c.isObject)(n[o])&&(0,c.isObject)(e[o])&&m(n[o],e[o],s,i):n[o]=e[o])}},g=(n,e,s)=>{if(!(0,c.isObject)(n)||!e.size)return n;const t=`${s}/`;let o=!1;for(const r of e)if(r.startsWith(t)){o=!0;break}if(!o)return n;const i={};for(const r in n){if(!Object.prototype.hasOwnProperty.call(n,r))continue;const a=`${s}/${r}`;e.has(a)||(i[r]=g(n[r],e,a))}return i},W=new Set,Y=new Set(["components","pages","functions","snippets","methods"]),L=(n,e)=>e===""&&Y.has(n),$=["fontFamily","fontfamily","font_family","FONT_FAMILY"],S=n=>{const e=new Map;if(!(0,c.isObject)(n))return e;for(const s of $){const t=n[s];if((0,c.isObject)(t))for(const o in t)!(0,c.isObject)(t[o])||!t[o].isDefault||(e.has(s)||e.set(s,new Set),e.get(s).add(o))}return e},A=(n,e)=>{for(const s of $){const t=n[s];if(!(0,c.isObject)(t))continue;const o=e.get(s);let i=null;for(const r in t){const a=t[r];if(!(0,c.isObject)(a)||!a.isDefault||o&&o.has(r))continue;const l={...a};delete l.isDefault,i||(i={...t}),i[r]=l}i&&(n[s]=i)}},J=n=>n.replace(/\.js$/iu,""),y=n=>{const e=new Set;if(!Array.isArray(n))return e;for(const s of n){if(!(0,c.isString)(s))continue;const t=s.split("/").map(o=>J(o.trim())).filter(Boolean).join("/");t&&e.add(t)}return e},V=(n,e={})=>({library:n,ignoreList:Array.isArray(e.ignoreList)?e.ignoreList:[]}),k=n=>(0,c.isObject)(n)&&Array.isArray(n.ignoreList)&&("library"in n||"key"in n||"name"in n),I=n=>n.library!==void 0?n.library:n.key??n.name,p=new Set,q=()=>{p.clear()},H=(n,e)=>{const s=e.filter(t=>!p.has(t));if(s.length){for(const t of s)p.add(t);(0,B.isLoudDevRuntime)()&&console.warn(`[smbls] shared library "${n}" ships ${s.map(t=>`methods.${t}`).join(", ")} \u2014 named like a built-in element method. Refused: the built-in wins; a library cannot replace an element method on the consuming app. If the app wants this version, declare it in the app's OWN methods.`)}},Q=(n,e,s)=>{let t=null;for(const o in n)if((0,u.isProtectedElementMethod)(o)&&(e.has(`methods/${o}`)||s.push(o),!t)){t={};for(const i in n)(0,u.isProtectedElementMethod)(i)||(t[i]=n[i])}return t||n},_=(n,e)=>{const s=y(n.sharedLibIgnore);return n.sharePages===!1&&s.add("pages"),s.size?new Set([...e,...s]):e},X=(n,e,s,t="library")=>{const o=_(e,s),i=[];for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)&&!(r==="sharePages"||r==="sharedLibIgnore")&&r!=="app"&&!o.has(r)){if((0,c.isObject)(e[r])&&(0,c.isObject)(n[r])){if(r==="designSystem")m(n[r],e[r],o,r);else for(const a in e[r])if(!o.has(`${r}/${a}`)){if(r==="methods"&&(0,u.isProtectedElementMethod)(a)){a in n[r]||i.push(a);continue}a in n[r]?L(r,n[r][a])&&!L(r,e[r][a])&&(n[r][a]=e[r][a]):n[r][a]=e[r][a]}}else if(!(r in n)){const a=e[r],l=r==="methods"&&a&&typeof a=="object"?Q(a,o,i):a;n[r]=g(l,o,r)}}i.length&&H(t,i)},Z=(n,e,s)=>{if(n!==e){const t=I(n);if((0,c.isString)(t)&&t)return t;if(n.key||n.name)return n.key||n.name}return e&&(e.key||e.name)||`sharedLibraries[${s}]`},x=`${h}/default`,nn=n=>(0,c.isString)(n)&&n!==""&&f(n).full===x,en=(n,e)=>{if((0,c.isString)(e.key)&&e.key)return e.key;if(n!==e){if((0,c.isString)(n.key)&&n.key)return n.key;if((0,c.isString)(n.name)&&n.name)return n.name}return null},tn=n=>{const e=[],s=[];for(let t=0;t<n.length;t++){const o=n[t];let i=o,r=W;if(k(i)&&(r=y(i.ignoreList),i=i.library),!(0,c.isObject)(i))continue;const a={entry:o,lib:i,ignore:r,index:t};nn(en(o,i))?s.push(a):e.push(a)}return{linked:e,bases:s}},R=(n,e,s)=>{const t=S(e()),{linked:o,bases:i}=tn(n);for(const a of o)s(a);const r=!t.size&&i.length?S(e()):null;for(const a of i)s(a);return t.size?t:r&&r.size?r:null},sn=(n,e)=>{if(!e||!e.length)return;const s=n.designSystem,t=R(e,()=>n.designSystem,({entry:o,lib:i,ignore:r,index:a})=>X(n,i,r,Z(o,i,a)));t&&(n.designSystem!==s&&(n.designSystem={...n.designSystem}),A(n.designSystem,t))},rn=(n,e,s=m)=>{if(!(0,c.isObject)(n)||!Array.isArray(e)||!e.length)return n;const t=R(e,()=>n,({lib:o,ignore:i})=>{const r=o.designSystem;if(!r||typeof r!="object")return;const a=_(o,i);a.has("designSystem")||s(n,r,a,"designSystem")});return t&&A(n,t),n};async function O(n,e={}){if((e.provider||"kv")==="api")return j(n,e);const t=await on(n,e);return t||j(n,e)}async function on(n,e={}){const s=e.kvBaseUrl||G,t=e.env||"production",o=`${s}/kv/${encodeURIComponent(n)}?env=${t}`;try{const i=await fetch(o,{method:"GET"});return i.ok&&(await i.json())?.value||null}catch{return null}}async function j(n,e={}){const s=e.apiBaseUrl||K,{key:t}=f(n);try{const o=`${s}/core/projects/libraries/available?search=${encodeURIComponent(t)}&limit=10`,i=await fetch(o,{method:"GET"});if(!i.ok)return null;const r=await i.json(),l=(r?.items||r?.data||(Array.isArray(r)?r:[])).find(U=>{const{key:F}=f(U?.key);return F.toLowerCase()===t.toLowerCase()});if(!l?.id&&!l?._id)return null;const E=l.id||l._id,P=`${s}/core/projects/${encodeURIComponent(E)}/data?branch=main`,w=await fetch(P,{method:"GET"});if(!w.ok)return null;const b=await w.json();return b?.data||b||null}catch{return null}}async function v(n,e={}){if((0,c.isObject)(n))return n;if((0,c.isString)(n)){const{full:s}=f(n);if(!s)return null;try{const t=await O(s,e);return t||console.warn(`[smbls] Shared library "${s}" not found`),t}catch(t){return console.warn(`[smbls] Failed to fetch shared library "${s}":`,t.message),null}}return null}async function an(n,e={}){return!n||!n.length?[]:(await Promise.all(n.map(async t=>{if(k(t)){const o=await v(I(t),e);return o?{library:o,ignoreList:t.ignoreList}:null}return v(t,e)}))).filter(Boolean)}
@@ -1,2 +1,2 @@
1
- import{isObject as S}from"./types.js";import{isStringFunction as M}from"./function.js";const a=r=>{if(r==null)return"";const o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return r.toString().replace(/[&<>"']/g,e=>o[e])},w=r=>Object.entries(r||{}).filter(([o,e])=>e!==void 0).map(([o,e])=>`${o}="${a(e)}"`).join(" "),j=r=>{let o=5381;const e=String(r);for(let t=0;t<e.length;t++)o=(o*33^e.charCodeAt(t))>>>0;return o.toString(36)},L=new Set(["jsonLd","styles","scripts"]),O=r=>{const o=[];if(Array.isArray(r.jsonLd))for(const e of r.jsonLd){if(e==null)continue;const t=typeof e=="string"?e:JSON.stringify(e),n=String(t).replace(/<\/script/gi,"<\\/script");o.push(`<script type="application/ld+json" data-smbls-jsonld="${j(t)}">${n}<\/script>`)}if(Array.isArray(r.styles))for(const e of r.styles){if(e==null||!String(e).trim())continue;const t=String(e).replace(/<\/style/gi,"<\\/style");o.push(`<style data-smbls-style="${j(t)}">${t}</style>`)}if(Array.isArray(r.scripts))for(const e of r.scripts){if(!e)continue;const t=typeof e=="string",n=t?e:e.src;if(!n&&!e.body)continue;const i=[];n&&i.push(`src="${a(n)}"`),t||(e.type&&i.push(`type="${a(e.type)}"`),e.async&&i.push("async"),e.defer&&i.push("defer"),e.integrity&&i.push(`integrity="${a(e.integrity)}"`),e.crossorigin&&i.push(`crossorigin="${a(e.crossorigin)}"`),e.referrerpolicy&&i.push(`referrerpolicy="${a(e.referrerpolicy)}"`),e.nomodule&&i.push("nomodule"));const f=` data-smbls-script="${a(n||j(e.body||""))}"`;if(!t&&e.body){const h=String(e.body).replace(/<\/script/gi,"<\\/script");o.push(`<script ${i.join(" ")}${f}>${h}<\/script>`)}else o.push(`<script ${i.join(" ")}${f}><\/script>`)}return o},F=(r,o)=>{o||(r={...r,robots:"noindex"});const e=Object.entries(r).reduce((t,[n,i])=>{if(!i&&i!==0&&i!==!1||L.has(n))return t;if(n==="title")return t.push(`<title>${a(i)}</title>`),t;if(n==="canonical")return t.push(`<link rel="canonical" href="${a(i)}">`),t;if(n==="manifest")return t.push(`<link rel="manifest" href="${a(i)}">`),t;if(n==="favicon"||n==="favicons"||n==="icon"||n==="icons")return(Array.isArray(i)?i:[i]).forEach(p=>{if(typeof p=="string")t.push(`<link rel="icon" href="${a(p)}">`);else if(typeof p=="object"){const u=w(p);/rel=/.test(u)?t.push(`<link ${u}>`):t.push(`<link rel="icon" ${u}>`)}}),t;if(n==="alternate")return(Array.isArray(i)?i:[i]).forEach(p=>{if(typeof p=="object"){const u=Object.entries(p).filter(([s,g])=>g!==void 0).map(([s,g])=>`${s}="${a(g)}"`).join(" ");t.push(`<link rel="alternate" ${u}>`)}}),t;const f=(l,p,u="name")=>{if(typeof p=="string"||typeof p=="number"||typeof p=="boolean")t.push(`<meta ${u}="${a(l)}" content="${a(p)}">`);else if(Array.isArray(p))p.forEach(s=>{if(typeof s=="string"||typeof s=="number"||typeof s=="boolean")t.push(`<meta ${u}="${a(l)}" content="${a(s)}">`);else if(typeof s=="object"){const g=Object.entries(s).filter(([d,c])=>c!==void 0).map(([d,c])=>`${d}="${a(c)}"`).join(" ");t.push(`<meta ${g}>`)}});else if(typeof p=="object"){const s=Object.entries(p).filter(([g,d])=>d!==void 0).map(([g,d])=>`${g}="${a(d)}"`).join(" ");t.push(`<meta ${s}>`)}};if(n.startsWith("http-equiv:")){const l=n.replace("http-equiv:","");return f(l,i,"http-equiv"),t}if(n.startsWith("itemprop:")){const l=n.replace("itemprop:","");return f(l,i,"itemprop"),t}const y=["og:","twitter:","fb:","article:","profile:","book:","business:","music:","product:","video:","DC:","DCTERMS:"].find(l=>n.startsWith(l));if(y){const l=n.replace(y,"");return f(`${y.replace(":","")}:${l}`,i,y==="twitter:"||y==="DC:"||y==="DCTERMS:"?"name":"property"),t}if(n.startsWith("apple:")||n.startsWith("msapplication:")){const l=n.startsWith("apple:")?"apple-":"msapplication-",p=n.replace(/^apple:|^msapplication:/,"");return f(`${l}${p}`,i,"name"),t}return f(n,i),t},['<meta charset="UTF-8">','<meta name="viewport" content="width=device-width, initial-scale=1">']);return e.push(...O(r)),e.join(`
2
- `)},E=r=>typeof r=="string"&&r.length>0&&!r.startsWith("/")&&!r.startsWith("http");function W(r,o){if(!o||typeof o!="object")return r;const e=n=>{if(!E(n))return n;const i=o[n];return i?.src?i.src:n},t={...r};for(const[n,i]of Object.entries(t))typeof i=="string"?t[n]=e(i):Array.isArray(i)&&(t[n]=i.map(f=>typeof f=="string"?e(f):f));return t}function m(r,o){if(!r||!o)return;const e=o.split(".");let t=r;for(const n of e){if(t==null||typeof t!="object")return;t=t[n]}return t}function T(r,o,e){const n=(o.config||o.settings||{}).polyglot||o.polyglot,i=e?.lang||n?.defaultLang||"en",h=(n?.translations||{})[i]||{},y=e?.state||{},l={...r};for(const[p,u]of Object.entries(l))typeof u!="string"||!u.includes("{{")||(l[p]=u.replace(/\{\{\s*([^|{}]+?)\s*(?:\|\s*(\w+)\s*)?\}\}/g,(s,g,d)=>{const c=g.trim();if(d==="polyglot")return h[c]??m(h,c)??s;if(d==="getLocalStateLang")return m(y,c+i)??s;const $=m(y,c);return $!==void 0?$:h[c]??m(h,c)??s}));return l}function A(r){if(!S(r))return{};const o={...r};for(const[e,t]of Object.entries(o))if(typeof t=="function"){const n=t.toString(),i=n.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(i){o[e]=`{{ ${i[1]} | getLocalStateLang }}`;continue}const f=n.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(f){o[e]=`{{ ${f[1]} | polyglot }}`;continue}const h=n.match(/s\.(\w+(?:\.\w+)+)/);if(h){o[e]=`{{ ${h[1]} }}`;continue}delete o[e]}else if(typeof t=="string"){const n=t.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(n){o[e]=`{{ ${n[1]} | getLocalStateLang }}`;continue}const i=t.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(i){o[e]=`{{ ${i[1]} | polyglot }}`;continue}if(t.includes("=>")&&t.includes("s.")){const f=t.match(/s\.(\w+(?:\.\w+)+)/);if(f){o[e]=`{{ ${f[1]} }}`;continue}}M(t)&&delete o[e]}return o}function R(r,o,e,{isProduction:t=!1,channel:n="production"}={}){const i=r.pages?.[o],f=S(i?.state)&&i?.state,h=i?.metadata||i?.helmet||f||{},y=A(h),l=new Set(Object.keys(y)),p=r.app?.metadata||{},u=A(p);let s={};if(r.integrations?.seo?s={...r.integrations.seo,...u,...y}:Object.keys(u).length?s={...u,...y}:s={...y},!s.title){const c=r.name||r.key;c?t?s.title=c:n==="development"?s.title=`${c} / dev:symbo.ls`:n==="staging"?s.title=`${c} / staging:symbo.ls`:s.title=`${c} / symbo.ls`:s.title="Symbols demo"}s=T(s,r,e),s.title&&(l.has("title")||!s["og:title"])&&(l.has("og:title")||(s["og:title"]=s.title)),s.description&&(l.has("description")||!s["og:description"])&&(l.has("og:description")||(s["og:description"]=s.description)),s.title&&!s["twitter:title"]&&(s["twitter:title"]=s.title),s.description&&!s["twitter:description"]&&(s["twitter:description"]=s.description);const g=e?.actualPathname||o;if(s["og:url"]||s.url){const c=(s["og:url"]||s.url||"").replace(/\/$/,"");if(c&&g&&g!=="/"){const $=g.startsWith("/")?g:"/"+g;s["og:url"]=c+$}}s=W(s,r.files);const d=r.name||r.app?.metadata?.title||r.app?.name||"";for(const[c,$]of Object.entries(s))if(typeof $=="string"&&$.includes("{{")){const b=$.replace(/\{\{[^}]*\}\}/g,"").trim();b?s[c]=b:c==="title"?s[c]=d:delete s[c]}return s}export{O as generateHeadArrayTags,F as generateMetaTags,R as getPageMetadata,j as hashContent};
1
+ import{isObject as A}from"./types.js";import{isStringFunction as w}from"./function.js";const g=n=>{if(n==null)return"";const r={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return n.toString().replace(/[&<>"']/g,t=>r[t])},O=n=>Object.entries(n||{}).filter(([r,t])=>t!==void 0).map(([r,t])=>`${r}="${g(t)}"`).join(" "),b=n=>{let r=5381;const t=String(n);for(let e=0;e<t.length;e++)r=(r*33^t.charCodeAt(e))>>>0;return r.toString(36)},L=new Set(["jsonLd","styles","scripts"]),E=n=>{const r=[];if(Array.isArray(n.jsonLd))for(const t of n.jsonLd){if(t==null)continue;const e=typeof t=="string"?t:JSON.stringify(t),i=String(e).replace(/<\/script/gi,"<\\/script");r.push(`<script type="application/ld+json" data-smbls-jsonld="${b(e)}">${i}<\/script>`)}if(Array.isArray(n.styles))for(const t of n.styles){if(t==null||!String(t).trim())continue;const e=String(t).replace(/<\/style/gi,"<\\/style");r.push(`<style data-smbls-style="${b(e)}">${e}</style>`)}if(Array.isArray(n.scripts))for(const t of n.scripts){if(!t)continue;const e=typeof t=="string",i=e?t:t.src;if(!i&&!t.body)continue;const o=[];i&&o.push(`src="${g(i)}"`),e||(t.type&&o.push(`type="${g(t.type)}"`),t.async&&o.push("async"),t.defer&&o.push("defer"),t.integrity&&o.push(`integrity="${g(t.integrity)}"`),t.crossorigin&&o.push(`crossorigin="${g(t.crossorigin)}"`),t.referrerpolicy&&o.push(`referrerpolicy="${g(t.referrerpolicy)}"`),t.nomodule&&o.push("nomodule"));const l=` data-smbls-script="${g(i||b(t.body||""))}"`;if(!e&&t.body){const h=String(t.body).replace(/<\/script/gi,"<\\/script");r.push(`<script ${o.join(" ")}${l}>${h}<\/script>`)}else r.push(`<script ${o.join(" ")}${l}><\/script>`)}return r},U=(n,r)=>{r||(n={...n,robots:"noindex"});const t=Object.entries(n).reduce((e,[i,o])=>{if(!o&&o!==0&&o!==!1||L.has(i))return e;if(i==="title")return e.push(`<title>${g(o)}</title>`),e;if(i==="canonical")return e.push(`<link rel="canonical" href="${g(o)}">`),e;if(i==="manifest")return e.push(`<link rel="manifest" href="${g(o)}">`),e;if(i==="favicon"||i==="favicons"||i==="icon"||i==="icons")return(Array.isArray(o)?o:[o]).forEach(c=>{if(typeof c=="string")e.push(`<link rel="icon" href="${g(c)}">`);else if(typeof c=="object"){const u=O(c);/rel=/.test(u)?e.push(`<link ${u}>`):e.push(`<link rel="icon" ${u}>`)}}),e;if(i==="alternate")return(Array.isArray(o)?o:[o]).forEach(c=>{if(typeof c=="object"){const u=Object.entries(c).filter(([s,p])=>p!==void 0).map(([s,p])=>`${s}="${g(p)}"`).join(" ");e.push(`<link rel="alternate" ${u}>`)}}),e;const l=(f,c,u="name")=>{if(typeof c=="string"||typeof c=="number"||typeof c=="boolean")e.push(`<meta ${u}="${g(f)}" content="${g(c)}">`);else if(Array.isArray(c))c.forEach(s=>{if(typeof s=="string"||typeof s=="number"||typeof s=="boolean")e.push(`<meta ${u}="${g(f)}" content="${g(s)}">`);else if(typeof s=="object"){const p=Object.entries(s).filter(([m,a])=>a!==void 0).map(([m,a])=>`${m}="${g(a)}"`).join(" ");e.push(`<meta ${p}>`)}});else if(typeof c=="object"){const s=Object.entries(c).filter(([p,m])=>m!==void 0).map(([p,m])=>`${p}="${g(m)}"`).join(" ");e.push(`<meta ${s}>`)}};if(i.startsWith("http-equiv:")){const f=i.replace("http-equiv:","");return l(f,o,"http-equiv"),e}if(i.startsWith("itemprop:")){const f=i.replace("itemprop:","");return l(f,o,"itemprop"),e}const y=["og:","twitter:","fb:","article:","profile:","book:","business:","music:","product:","video:","DC:","DCTERMS:"].find(f=>i.startsWith(f));if(y){const f=i.replace(y,"");return l(`${y.replace(":","")}:${f}`,o,y==="twitter:"||y==="DC:"||y==="DCTERMS:"?"name":"property"),e}if(i.startsWith("apple:")||i.startsWith("msapplication:")){const f=i.startsWith("apple:")?"apple-":"msapplication-",c=i.replace(/^apple:|^msapplication:/,"");return l(`${f}${c}`,o,"name"),e}return l(i,o),e},['<meta charset="UTF-8">','<meta name="viewport" content="width=device-width, initial-scale=1">']);return t.push(...E(n)),t.join(`
2
+ `)},W=n=>typeof n=="string"&&n.length>0&&!n.startsWith("/")&&!n.startsWith("http"),j=n=>typeof n=="string"&&n.length>0,x=n=>{if(!n||typeof n!="object")return null;if(j(n.src))return n.src;const r=n.content;return!r||typeof r!="object"?null:j(r.src)?r.src:j(r.storageUrl)?r.storageUrl:null};function T(n,r){if(!r||typeof r!="object")return n;const t=i=>!W(i)||!Object.prototype.hasOwnProperty.call(r,i)?i:x(r[i])||i,e={...n};for(const[i,o]of Object.entries(e))typeof o=="string"?e[i]=t(o):Array.isArray(o)&&(e[i]=o.map(l=>typeof l=="string"?t(l):l));return e}function S(n,r){if(!n||!r)return;const t=r.split(".");let e=n;for(const i of t){if(e==null||typeof e!="object")return;e=e[i]}return e}function F(n,r){const t=S(n,r);if(typeof t=="number")return Number.isFinite(t)?t:void 0;if(typeof t=="string"&&!w(t))return t}function D(n,r,t){const i=(r.config||r.settings||{}).polyglot||r.polyglot,o=t?.lang||i?.defaultLang||"en",h=(i?.translations||{})[o]||{},y=[t?.state,r.state].filter(u=>u&&typeof u=="object"),f=u=>{for(const s of y){const p=F(s,u);if(p!==void 0)return p}},c={...n};for(const[u,s]of Object.entries(c))typeof s!="string"||!s.includes("{{")||(c[u]=s.replace(/\{\{\s*([^|{}]+?)\s*(?:\|\s*(\w+)\s*)?\}\}/g,(p,m,a)=>{const d=m.trim();if(a==="polyglot")return h[d]??S(h,d)??p;if(a==="getLocalStateLang")return f(d+o)??p;const $=f(d);return $!==void 0?$:h[d]??S(h,d)??p}));return c}function M(n){if(!A(n))return{};const r={...n};for(const[t,e]of Object.entries(r))if(typeof e=="function"){const i=e.toString(),o=i.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(o){r[t]=`{{ ${o[1]} | getLocalStateLang }}`;continue}const l=i.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(l){r[t]=`{{ ${l[1]} | polyglot }}`;continue}const h=i.match(/s\.(\w+(?:\.\w+)+)/);if(h){r[t]=`{{ ${h[1]} }}`;continue}delete r[t]}else if(typeof e=="string"){const i=e.match(/el\.call\(\s*["']getLocalStateLang["']\s*,\s*["']([^"']+)["']\s*\)/);if(i){r[t]=`{{ ${i[1]} | getLocalStateLang }}`;continue}const o=e.match(/el\.call\(\s*["']polyglot["']\s*,\s*["']([^"']+)["']\s*\)/);if(o){r[t]=`{{ ${o[1]} | polyglot }}`;continue}if(e.includes("=>")&&e.includes("s.")){const l=e.match(/s\.(\w+(?:\.\w+)+)/);if(l){r[t]=`{{ ${l[1]} }}`;continue}}w(e)&&delete r[t]}return r}function _(n,r,t,{isProduction:e=!1,channel:i="production"}={}){const o=n.pages?.[r],l=A(o?.state)&&o?.state,h=o?.metadata||o?.helmet||l||{},y=M(h),f=new Set(Object.keys(y)),c=n.app?.metadata||{},u=M(c);let s={};if(n.integrations?.seo?s={...n.integrations.seo,...u,...y}:Object.keys(u).length?s={...u,...y}:s={...y},!s.title){const a=n.name||n.key;a?e?s.title=a:i==="development"?s.title=`${a} / dev:symbo.ls`:i==="staging"?s.title=`${a} / staging:symbo.ls`:s.title=`${a} / symbo.ls`:s.title="Symbols demo"}s=D(s,n,t),s.title&&(f.has("title")||!s["og:title"])&&(f.has("og:title")||(s["og:title"]=s.title)),s.description&&(f.has("description")||!s["og:description"])&&(f.has("og:description")||(s["og:description"]=s.description)),s.title&&!s["twitter:title"]&&(s["twitter:title"]=s.title),s.description&&!s["twitter:description"]&&(s["twitter:description"]=s.description);const p=t?.actualPathname||r;if(s["og:url"]||s.url){const a=(s["og:url"]||s.url||"").replace(/\/$/,"");if(a&&p&&p!=="/"){const d=p.startsWith("/")?p:"/"+p;s["og:url"]=a+d}}s=T(s,n.files);const m=n.name||n.app?.metadata?.title||n.app?.name||"";for(const[a,d]of Object.entries(s))if(typeof d=="string"&&d.includes("{{")){const $=d.replace(/\{\{[^}]*\}\}/g,"").trim();$?s[a]=$:a==="title"?s[a]=m:delete s[a]}return s}export{x as fileEntryUrl,E as generateHeadArrayTags,U as generateMetaTags,_ as getPageMetadata,b as hashContent,T as resolveFileReferences};
@@ -1 +1 @@
1
- import{isObject as l,isString as u}from"./types.js";import{isProtectedElementMethod as d}from"./keys.js";import{isLoudDevRuntime as O}from"./env.js";const w="system",B="https://smbls-kv.nika-980.workers.dev",E="https://api.symbols.app";function h(n){const t=String(n||"").trim();if(!t)return{owner:w,key:"",full:""};let o=null,e=t;if(t.includes("/")){const r=t.indexOf("/");o=t.slice(0,r),e=t.slice(r+1)}e=e.replace(/\.symbo\.ls$/iu,""),o||(o=w);const s=e?`${o}/${e}`:"";return{owner:o,key:e,full:s}}const b=(n,t,o,e)=>{for(const s in t){const r=e?`${e}/${s}`:s;o&&o.has(r)||(s in n?l(n[s])&&l(t[s])&&b(n[s],t[s],o,r):n[s]=t[s])}},g=(n,t,o)=>{if(!l(n)||!t.size)return n;const e=`${o}/`;let s=!1;for(const a of t)if(a.startsWith(e)){s=!0;break}if(!s)return n;const r={};for(const a in n){if(!Object.prototype.hasOwnProperty.call(n,a))continue;const i=`${o}/${a}`;t.has(i)||(r[a]=g(n[a],t,i))}return r},F=new Set,U=new Set(["components","pages","functions","snippets","methods"]),k=(n,t)=>t===""&&U.has(n),$=["fontFamily","fontfamily","font_family","FONT_FAMILY"],P=n=>{const t=new Map;if(!l(n))return t;for(const o of $){const e=n[o];if(l(e))for(const s in e)!l(e[s])||!e[s].isDefault||(t.has(o)||t.set(o,new Set),t.get(o).add(s))}return t},M=(n,t)=>{for(const o of $){const e=n[o];if(!l(e))continue;const s=t.get(o);let r=null;for(const a in e){const i=e[a];if(!l(i)||!i.isDefault||s&&s.has(a))continue;const c={...i};delete c.isDefault,r||(r={...e}),r[a]=c}r&&(n[o]=r)}},D=n=>n.replace(/\.js$/iu,""),L=n=>{const t=new Set;if(!Array.isArray(n))return t;for(const o of n){if(!u(o))continue;const e=o.split("/").map(s=>D(s.trim())).filter(Boolean).join("/");e&&t.add(e)}return t},x=(n,t={})=>({library:n,ignoreList:Array.isArray(t.ignoreList)?t.ignoreList:[]}),A=n=>l(n)&&Array.isArray(n.ignoreList)&&("library"in n||"key"in n||"name"in n),S=n=>n.library!==void 0?n.library:n.key??n.name,m=new Set,V=()=>{m.clear()},T=(n,t)=>{const o=t.filter(e=>!m.has(e));if(o.length){for(const e of o)m.add(e);O()&&console.warn(`[smbls] shared library "${n}" ships ${o.map(e=>`methods.${e}`).join(", ")} \u2014 named like a built-in element method. Refused: the built-in wins; a library cannot replace an element method on the consuming app. If the app wants this version, declare it in the app's OWN methods.`)}},C=(n,t,o)=>{let e=null;for(const s in n)if(d(s)&&(t.has(`methods/${s}`)||o.push(s),!e)){e={};for(const r in n)d(r)||(e[r]=n[r])}return e||n},N=(n,t,o,e="library")=>{const s=L(t.sharedLibIgnore);t.sharePages===!1&&s.add("pages");const r=s.size?new Set([...o,...s]):o,a=[];for(const i in t)if(Object.prototype.hasOwnProperty.call(t,i)&&!(i==="sharePages"||i==="sharedLibIgnore")&&i!=="app"&&!r.has(i)){if(l(t[i])&&l(n[i])){if(i==="designSystem")b(n[i],t[i],r,i);else for(const c in t[i])if(!r.has(`${i}/${c}`)){if(i==="methods"&&d(c)){c in n[i]||a.push(c);continue}c in n[i]?k(i,n[i][c])&&!k(i,t[i][c])&&(n[i][c]=t[i][c]):n[i][c]=t[i][c]}}else if(!(i in n)){const c=t[i],f=i==="methods"&&c&&typeof c=="object"?C(c,r,a):c;n[i]=g(f,r,i)}}a.length&&T(e,a)},G=(n,t,o)=>{if(n!==t){const e=S(n);if(u(e)&&e)return e;if(n.key||n.name)return n.key||n.name}return t&&(t.key||t.name)||`sharedLibraries[${o}]`},q=(n,t)=>{if(!t||!t.length)return;const o=P(n.designSystem);for(let e=0;e<t.length;e++){const s=t[e];let r=s,a=F;A(r)&&(a=L(r.ignoreList),r=r.library),l(r)&&N(n,r,a,G(s,r,e))}o.size&&M(n.designSystem,o)};async function W(n,t={}){if((t.provider||"kv")==="api")return _(n,t);const e=await z(n,t);return e||_(n,t)}async function z(n,t={}){const o=t.kvBaseUrl||B,e=t.env||"production",s=`${o}/kv/${encodeURIComponent(n)}?env=${e}`;try{const r=await fetch(s,{method:"GET"});return r.ok&&(await r.json())?.value||null}catch{return null}}async function _(n,t={}){const o=t.apiBaseUrl||E,{key:e}=h(n);try{const s=`${o}/core/projects/libraries/available?search=${encodeURIComponent(e)}&limit=10`,r=await fetch(s,{method:"GET"});if(!r.ok)return null;const a=await r.json(),c=(a?.items||a?.data||(Array.isArray(a)?a:[])).find(j=>{const{key:R}=h(j?.key);return R.toLowerCase()===e.toLowerCase()});if(!c?.id&&!c?._id)return null;const f=c.id||c._id,I=`${o}/core/projects/${encodeURIComponent(f)}/data?branch=main`,p=await fetch(I,{method:"GET"});if(!p.ok)return null;const y=await p.json();return y?.data||y||null}catch{return null}}async function v(n,t={}){if(l(n))return n;if(u(n)){const{full:o}=h(n);if(!o)return null;try{const e=await W(o,t);return e||console.warn(`[smbls] Shared library "${o}" not found`),e}catch(e){return console.warn(`[smbls] Failed to fetch shared library "${o}":`,e.message),null}}return null}async function H(n,t={}){return!n||!n.length?[]:(await Promise.all(n.map(async e=>{if(A(e)){const s=await v(S(e),t);return s?{library:s,ignoreList:e.ignoreList}:null}return v(e,t)}))).filter(Boolean)}export{V as __resetBuiltinMethodWarnings,b as deepDefaults,W as fetchLibraryData,A as isWrappedLibrary,q as mergeSharedLibraries,L as normalizeIgnoreList,h as normalizeLibraryKey,H as resolveSharedLibraries,x as sharedLibrary};
1
+ import{isObject as c,isString as f}from"./types.js";import{isProtectedElementMethod as m}from"./keys.js";import{isLoudDevRuntime as U}from"./env.js";const d="system",F="https://smbls-kv.nika-980.workers.dev",M="https://api.symbols.app";function u(n){const e=String(n||"").trim();if(!e)return{owner:d,key:"",full:""};let s=null,t=e;if(e.includes("/")){const i=e.indexOf("/");s=e.slice(0,i),t=e.slice(i+1)}t=t.replace(/\.symbo\.ls$/iu,""),s||(s=d);const o=t?`${s}/${t}`:"";return{owner:s,key:t,full:o}}const h=(n,e,s,t)=>{for(const o in e){const i=t?`${t}/${o}`:o;s&&s.has(i)||(o in n?c(n[o])&&c(e[o])&&h(n[o],e[o],s,i):n[o]=e[o])}},w=(n,e,s)=>{if(!c(n)||!e.size)return n;const t=`${s}/`;let o=!1;for(const r of e)if(r.startsWith(t)){o=!0;break}if(!o)return n;const i={};for(const r in n){if(!Object.prototype.hasOwnProperty.call(n,r))continue;const a=`${s}/${r}`;e.has(a)||(i[r]=w(n[r],e,a))}return i},C=new Set,D=new Set(["components","pages","functions","snippets","methods"]),b=(n,e)=>e===""&&D.has(n),g=["fontFamily","fontfamily","font_family","FONT_FAMILY"],L=n=>{const e=new Map;if(!c(n))return e;for(const s of g){const t=n[s];if(c(t))for(const o in t)!c(t[o])||!t[o].isDefault||(e.has(s)||e.set(s,new Set),e.get(s).add(o))}return e},$=(n,e)=>{for(const s of g){const t=n[s];if(!c(t))continue;const o=e.get(s);let i=null;for(const r in t){const a=t[r];if(!c(a)||!a.isDefault||o&&o.has(r))continue;const l={...a};delete l.isDefault,i||(i={...t}),i[r]=l}i&&(n[s]=i)}},T=n=>n.replace(/\.js$/iu,""),S=n=>{const e=new Set;if(!Array.isArray(n))return e;for(const s of n){if(!f(s))continue;const t=s.split("/").map(o=>T(o.trim())).filter(Boolean).join("/");t&&e.add(t)}return e},x=(n,e={})=>({library:n,ignoreList:Array.isArray(e.ignoreList)?e.ignoreList:[]}),A=n=>c(n)&&Array.isArray(n.ignoreList)&&("library"in n||"key"in n||"name"in n),I=n=>n.library!==void 0?n.library:n.key??n.name,p=new Set,nn=()=>{p.clear()},z=(n,e)=>{const s=e.filter(t=>!p.has(t));if(s.length){for(const t of s)p.add(t);U()&&console.warn(`[smbls] shared library "${n}" ships ${s.map(t=>`methods.${t}`).join(", ")} \u2014 named like a built-in element method. Refused: the built-in wins; a library cannot replace an element method on the consuming app. If the app wants this version, declare it in the app's OWN methods.`)}},N=(n,e,s)=>{let t=null;for(const o in n)if(m(o)&&(e.has(`methods/${o}`)||s.push(o),!t)){t={};for(const i in n)m(i)||(t[i]=n[i])}return t||n},_=(n,e)=>{const s=S(n.sharedLibIgnore);return n.sharePages===!1&&s.add("pages"),s.size?new Set([...e,...s]):e},G=(n,e,s,t="library")=>{const o=_(e,s),i=[];for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)&&!(r==="sharePages"||r==="sharedLibIgnore")&&r!=="app"&&!o.has(r)){if(c(e[r])&&c(n[r])){if(r==="designSystem")h(n[r],e[r],o,r);else for(const a in e[r])if(!o.has(`${r}/${a}`)){if(r==="methods"&&m(a)){a in n[r]||i.push(a);continue}a in n[r]?b(r,n[r][a])&&!b(r,e[r][a])&&(n[r][a]=e[r][a]):n[r][a]=e[r][a]}}else if(!(r in n)){const a=e[r],l=r==="methods"&&a&&typeof a=="object"?N(a,o,i):a;n[r]=w(l,o,r)}}i.length&&z(t,i)},K=(n,e,s)=>{if(n!==e){const t=I(n);if(f(t)&&t)return t;if(n.key||n.name)return n.key||n.name}return e&&(e.key||e.name)||`sharedLibraries[${s}]`},W=`${d}/default`,Y=n=>f(n)&&n!==""&&u(n).full===W,J=(n,e)=>{if(f(e.key)&&e.key)return e.key;if(n!==e){if(f(n.key)&&n.key)return n.key;if(f(n.name)&&n.name)return n.name}return null},V=n=>{const e=[],s=[];for(let t=0;t<n.length;t++){const o=n[t];let i=o,r=C;if(A(i)&&(r=S(i.ignoreList),i=i.library),!c(i))continue;const a={entry:o,lib:i,ignore:r,index:t};Y(J(o,i))?s.push(a):e.push(a)}return{linked:e,bases:s}},R=(n,e,s)=>{const t=L(e()),{linked:o,bases:i}=V(n);for(const a of o)s(a);const r=!t.size&&i.length?L(e()):null;for(const a of i)s(a);return t.size?t:r&&r.size?r:null},en=(n,e)=>{if(!e||!e.length)return;const s=n.designSystem,t=R(e,()=>n.designSystem,({entry:o,lib:i,ignore:r,index:a})=>G(n,i,r,K(o,i,a)));t&&(n.designSystem!==s&&(n.designSystem={...n.designSystem}),$(n.designSystem,t))},tn=(n,e,s=h)=>{if(!c(n)||!Array.isArray(e)||!e.length)return n;const t=R(e,()=>n,({lib:o,ignore:i})=>{const r=o.designSystem;if(!r||typeof r!="object")return;const a=_(o,i);a.has("designSystem")||s(n,r,a,"designSystem")});return t&&$(n,t),n};async function q(n,e={}){if((e.provider||"kv")==="api")return j(n,e);const t=await H(n,e);return t||j(n,e)}async function H(n,e={}){const s=e.kvBaseUrl||F,t=e.env||"production",o=`${s}/kv/${encodeURIComponent(n)}?env=${t}`;try{const i=await fetch(o,{method:"GET"});return i.ok&&(await i.json())?.value||null}catch{return null}}async function j(n,e={}){const s=e.apiBaseUrl||M,{key:t}=u(n);try{const o=`${s}/core/projects/libraries/available?search=${encodeURIComponent(t)}&limit=10`,i=await fetch(o,{method:"GET"});if(!i.ok)return null;const r=await i.json(),l=(r?.items||r?.data||(Array.isArray(r)?r:[])).find(E=>{const{key:P}=u(E?.key);return P.toLowerCase()===t.toLowerCase()});if(!l?.id&&!l?._id)return null;const B=l.id||l._id,O=`${s}/core/projects/${encodeURIComponent(B)}/data?branch=main`,y=await fetch(O,{method:"GET"});if(!y.ok)return null;const k=await y.json();return k?.data||k||null}catch{return null}}async function v(n,e={}){if(c(n))return n;if(f(n)){const{full:s}=u(n);if(!s)return null;try{const t=await q(s,e);return t||console.warn(`[smbls] Shared library "${s}" not found`),t}catch(t){return console.warn(`[smbls] Failed to fetch shared library "${s}":`,t.message),null}}return null}async function sn(n,e={}){return!n||!n.length?[]:(await Promise.all(n.map(async t=>{if(A(t)){const o=await v(I(t),e);return o?{library:o,ignoreList:t.ignoreList}:null}return v(t,e)}))).filter(Boolean)}export{nn as __resetBuiltinMethodWarnings,h as deepDefaults,q as fetchLibraryData,A as isWrappedLibrary,en as mergeSharedLibraries,tn as mergeSharedLibraryDesignSystems,S as normalizeIgnoreList,u as normalizeLibraryKey,sn as resolveSharedLibraries,x as sharedLibrary};
package/metadata.js CHANGED
@@ -270,19 +270,56 @@ export const generateMetaTags = (metadata, isProduction) => {
270
270
  const isBareFilename = (val) =>
271
271
  typeof val === 'string' && val.length > 0 && !val.startsWith('/') && !val.startsWith('http')
272
272
 
273
+ const nonEmptyString = (v) => typeof v === 'string' && v.length > 0
274
+
275
+ /**
276
+ * The public URL a `data.files` entry carries, or null.
277
+ *
278
+ * A project's files map holds three entry shapes (measured 2026-10-02 over
279
+ * the /get payloads of 33 projects, 1544 entries):
280
+ *
281
+ * - a platform file record (1542): `{ content: { src, storageUrl?, urls?,
282
+ * … }, code, key, type, format }`. Its public address is `content.src`;
283
+ * there is no top-level `src`.
284
+ * - a hand-written external entry (1): `{ content: { storageUrl } }` — a big
285
+ * asset kept in its own bucket, with no `content.src`.
286
+ * - a manifest entry (1): `{ src }`.
287
+ *
288
+ * Reading only `entry.src` left every platform record's key bare in the
289
+ * static head (`og:image` = "site-social.jpg"). `src` stays first; then
290
+ * `content.src`, the address the runtime (attrs-in-props, `resolveAsset`)
291
+ * renders for the same key, so the head and the body agree; then
292
+ * `content.storageUrl`.
293
+ */
294
+ export const fileEntryUrl = (entry) => {
295
+ if (!entry || typeof entry !== 'object') return null
296
+ if (nonEmptyString(entry.src)) return entry.src
297
+ const content = entry.content
298
+ if (!content || typeof content !== 'object') return null
299
+ if (nonEmptyString(content.src)) return content.src
300
+ if (nonEmptyString(content.storageUrl)) return content.storageUrl
301
+ return null
302
+ }
303
+
273
304
  /**
274
305
  * Resolve bare filename references in metadata values against `data.files`.
275
306
  * If a metadata value is a plain filename (e.g. "logo.png") and a matching
276
- * entry exists in `data.files`, replace it with the file's `src` URL.
307
+ * entry exists in `data.files`, replace it with the file's URL
308
+ * (`fileEntryUrl`).
309
+ *
310
+ * The ONE rule for a files key in metadata: the static head here and every
311
+ * helmet path (extractMetadata, and the browser's create/update/define apply
312
+ * against `element.context.files`) call it, so the live <head> carries the
313
+ * same URL the server rendered instead of overwriting it with the bare key.
277
314
  */
278
- function resolveFileReferences (metadata, files) {
315
+ export function resolveFileReferences (metadata, files) {
279
316
  if (!files || typeof files !== 'object') return metadata
280
317
 
281
318
  const resolve = (val) => {
282
319
  if (!isBareFilename(val)) return val
283
- const fileEntry = files[val]
284
- if (fileEntry?.src) return fileEntry.src
285
- return val
320
+ // own keys only: a value like "constructor" is copy, not a file
321
+ if (!Object.prototype.hasOwnProperty.call(files, val)) return val
322
+ return fileEntryUrl(files[val]) || val
286
323
  }
287
324
 
288
325
  const result = { ...metadata }
@@ -312,9 +349,36 @@ function resolveDotPath (obj, path) {
312
349
  return v
313
350
  }
314
351
 
352
+ /**
353
+ * The value at `path` in `obj` when it is one a `{{ }}` template can print:
354
+ * a string or a finite number. Anything else answers undefined, so the lookup
355
+ * moves on to the next source instead of printing it:
356
+ * - an object or array would print "[object Object]" (the runtime's
357
+ * `replaceLiteralsWithObjectFields` skips them the same way);
358
+ * - a function's source would print code into a content attribute;
359
+ * - a boolean is a flag, never a head value. A converted factory such as
360
+ * `(el, s) => s.menu.open ? 'A' : 'B'` becomes `{{ menu.open }}` (the
361
+ * conversion keeps only the first state path), and printing its flag
362
+ * would put "false" where the factory returned a title.
363
+ */
364
+ function templateValueAt (obj, path) {
365
+ const v = resolveDotPath(obj, path)
366
+ if (typeof v === 'number') return Number.isFinite(v) ? v : undefined
367
+ if (typeof v === 'string' && !isStringFunction(v)) return v
368
+ return undefined
369
+ }
370
+
315
371
  /**
316
372
  * Resolve {{ key | polyglot }} and {{ key | getLocalStateLang }} templates
317
- * in metadata string values using project polyglot translations and SSR state.
373
+ * in metadata string values using project polyglot translations and state.
374
+ *
375
+ * State is read from two sources, in order: the page's PREFETCHED state
376
+ * (`ssrContext.state`), then the project's own state (`data.state`, the
377
+ * project's state.js — the root state the runtime factory read). Before the
378
+ * second source, a value kept in state.js never reached the static head
379
+ * unless a prefetch happened to carry it: `(el, s) => s.company.name` became
380
+ * `{{ company.name }}` and was stripped. The lookup is per path, so a
381
+ * prefetched state that lacks one path still falls back for it.
318
382
  */
319
383
  function resolveMetadataTemplates (metadata, data, ssrContext) {
320
384
  const config = data.config || data.settings || {}
@@ -322,7 +386,15 @@ function resolveMetadataTemplates (metadata, data, ssrContext) {
322
386
  const defaultLang = ssrContext?.lang || polyglot?.defaultLang || 'en'
323
387
  const translations = polyglot?.translations || {}
324
388
  const langMap = translations[defaultLang] || {}
325
- const state = ssrContext?.state || {}
389
+ const states = [ssrContext?.state, data.state].filter((s) => s && typeof s === 'object')
390
+
391
+ const fromState = (path) => {
392
+ for (const state of states) {
393
+ const v = templateValueAt(state, path)
394
+ if (v !== undefined) return v
395
+ }
396
+ return undefined
397
+ }
326
398
 
327
399
  const result = { ...metadata }
328
400
  for (const [key, value] of Object.entries(result)) {
@@ -337,13 +409,12 @@ function resolveMetadataTemplates (metadata, data, ssrContext) {
337
409
 
338
410
  if (filter === 'getLocalStateLang') {
339
411
  // key is like "item.title_" — append lang
340
- const resolved = resolveDotPath(state, trimmed + defaultLang)
341
- return resolved ?? match
412
+ return fromState(trimmed + defaultLang) ?? match
342
413
  }
343
414
 
344
415
  // No filter — try state lookup, then polyglot
345
- const fromState = resolveDotPath(state, trimmed)
346
- if (fromState !== undefined) return fromState
416
+ const stateValue = fromState(trimmed)
417
+ if (stateValue !== undefined) return stateValue
347
418
 
348
419
  return langMap[trimmed] ?? resolveDotPath(langMap, trimmed) ?? match
349
420
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/utils",
3
- "version": "3.14.779",
3
+ "version": "3.14.781",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./dist/esm/index.js",
@@ -124,8 +124,9 @@ const OBJECT_BAGS = new Set(['components', 'pages', 'functions', 'snippets', 'me
124
124
  * a value a library can legitimately mean — it is only ever that signature.
125
125
  *
126
126
  * This matters because the merge below is FIRST-WINS, which is correct for
127
- * real values (an earlier declaration outranks a later one, and the consumer
128
- * outranks every library) but wrong for a phantom: an earlier library's `""`
127
+ * real values (an earlier declaration outranks a later one, the consumer
128
+ * outranks every library, and the base library merges last — see
129
+ * `isBaseLibraryKey`) but wrong for a phantom: an earlier library's `""`
129
130
  * would permanently shadow the real object a LATER declared library carries
130
131
  * under the same name, and the consumer that declared the good library would
131
132
  * still get `""`. Measured live 2026-08-21 on the published `workspace-ui`
@@ -191,15 +192,17 @@ const defaultFontClaims = (designSystem) => {
191
192
  * bag the consumer did not have is the LIBRARY's own object, shared with
192
193
  * every other consumer of that library.
193
194
  *
194
- * When the consumer claims nothing, nothing changes: a library default is
195
- * what such a project has always rendered, and the order between two
196
- * libraries stays scratch's.
195
+ * When the consumer claims nothing, the same rule ranks the base library
196
+ * below the libraries the project linked: a linked library's claim stands and
197
+ * the base's (system/default's `Default`) yields — see `mergeInPrecedenceOrder`.
198
+ * Between two claims of one tier — two linked libraries, say — the order
199
+ * stays scratch's.
197
200
  */
198
- const yieldLibraryDefaultFonts = (designSystem, ownClaims) => {
201
+ const yieldLibraryDefaultFonts = (designSystem, winningClaims) => {
199
202
  for (const bag of FONT_FAMILY_BAGS) {
200
203
  const families = designSystem[bag]
201
204
  if (!isObject(families)) continue
202
- const own = ownClaims.get(bag)
205
+ const own = winningClaims.get(bag)
203
206
  let copy = null
204
207
  for (const k in families) {
205
208
  const entry = families[k]
@@ -334,20 +337,25 @@ const withoutProtectedMethods = (bag, skip, refused) => {
334
337
  return copy || bag
335
338
  }
336
339
 
337
- const mergeOneLibrary = (context, sharedLib, ignore, label = 'library') => {
338
- // A library can declare parts of itself private via `sharedLibIgnore` on
339
- // its own context — same path grammar as the consumer-side `ignoreList`
340
- // (top-level keys or nested 'components/Header'). A library serving its
341
- // own doc site (e.g. system/brand with `sharedLibIgnore: ['pages']`)
342
- // must be able to keep its routes out of every consumer; without it,
343
- // library pages auto-mount into any consumer that doesn't define the same
344
- // route key. `sharePages: false` is the earlier, narrower alias — kept
345
- // working, superseded by sharedLibIgnore.
340
+ // The paths one library's merge skips: the consumer's `ignoreList` for it plus
341
+ // the library's own declaration. A library can declare parts of itself private
342
+ // via `sharedLibIgnore` on its own context — same path grammar as the
343
+ // consumer-side `ignoreList` (top-level keys or nested 'components/Header'). A
344
+ // library serving its own doc site (e.g. system/brand with
345
+ // `sharedLibIgnore: ['pages']`) must be able to keep its routes out of every
346
+ // consumer; without it, library pages auto-mount into any consumer that
347
+ // doesn't define the same route key. `sharePages: false` is the earlier,
348
+ // narrower alias — kept working, superseded by sharedLibIgnore.
349
+ const librarySkip = (sharedLib, ignore) => {
346
350
  const libIgnore = normalizeIgnoreList(sharedLib.sharedLibIgnore)
347
351
  if (sharedLib.sharePages === false) libIgnore.add('pages')
348
- const skip = libIgnore.size
352
+ return libIgnore.size
349
353
  ? new Set([...ignore, ...libIgnore])
350
354
  : ignore
355
+ }
356
+
357
+ const mergeOneLibrary = (context, sharedLib, ignore, label = 'library') => {
358
+ const skip = librarySkip(sharedLib, ignore)
351
359
  const refusedMethods = []
352
360
  for (const key in sharedLib) {
353
361
  if (!Object.prototype.hasOwnProperty.call(sharedLib, key)) continue
@@ -414,6 +422,100 @@ const libraryLabel = (entry, lib, index) => {
414
422
  return (lib && (lib.key || lib.name)) || `sharedLibraries[${index}]`
415
423
  }
416
424
 
425
+ /**
426
+ * THE BASE LIBRARY — `system/default`.
427
+ *
428
+ * Every platform project starts linked to `system/default`: the hosted copy of
429
+ * the framework's own defaults (a design system, the default component kit).
430
+ * It is the base a project builds on, not a library the project chose: the
431
+ * CLI calls it the one framework-owned library key
432
+ * (packages/cli/helpers/libraryKeyUtils.js `FRAMEWORK_BUILTIN_LIBRARY_SLUGS`),
433
+ * and where it is not linked the framework's own defaults stand in for it
434
+ * BELOW every library (`@symbo.ls/default-config`, merged after this merge by
435
+ * smbls prepare.js `prepareDesignSystem` / `prepareComponents`).
436
+ *
437
+ * So it merges LAST, whatever its position in `sharedLibraries`: it fills only
438
+ * what no linked library defines. Measured 2026-10-02 on the published path: a
439
+ * consumer that links system/default AND unreal/brand rendered system/default's
440
+ * colours title, caption, paragraph and line and its `document` theme (body
441
+ * #F6F6F8 on #171717, not the brand's #EDEFF1 on #0A0B0D) whatever the order
442
+ * of the links on the platform record. The platform serves the direct
443
+ * libraries in ascending record-id order and system/default is the oldest
444
+ * record, so it was `sharedLibraries[0]` and won every token the two share
445
+ * under this first-wins merge. With the brand alone the brand rendered: the
446
+ * brand's own link to system/default is served after the brand.
447
+ *
448
+ * Recognised by its key in any spelling `normalizeLibraryKey` folds: 'default'
449
+ * (the served payload carries the bare key), 'system/default',
450
+ * 'default.symbo.ls'. Another owner's `default` is an ordinary library.
451
+ */
452
+ const BASE_LIBRARY = `${DEFAULT_LIBRARY_OWNER}/default`
453
+
454
+ const isBaseLibraryKey = (raw) =>
455
+ isString(raw) && raw !== '' && normalizeLibraryKey(raw).full === BASE_LIBRARY
456
+
457
+ // The key a merge entry names its library by: the library's own `key`, else a
458
+ // wrapped entry's `key` / `name` (the symbols.json-shaped
459
+ // `{ key, library, ignoreList }`). A library's `name` is a display name, never
460
+ // an identifier, so it is not read.
461
+ const entryLibraryKey = (entry, lib) => {
462
+ if (isString(lib.key) && lib.key) return lib.key
463
+ if (entry !== lib) {
464
+ if (isString(entry.key) && entry.key) return entry.key
465
+ if (isString(entry.name) && entry.name) return entry.name
466
+ }
467
+ return null
468
+ }
469
+
470
+ // `libraries` unwrapped and in merge order: the linked libraries in
471
+ // declaration order, then the base. An entry that is not a library object is
472
+ // dropped, as the merge always did.
473
+ const inMergeOrder = (libraries) => {
474
+ const linked = []
475
+ const bases = []
476
+ for (let i = 0; i < libraries.length; i++) {
477
+ const entry = libraries[i]
478
+ let lib = entry
479
+ let ignore = EMPTY_IGNORE
480
+ if (isWrappedLibrary(lib)) {
481
+ ignore = normalizeIgnoreList(lib.ignoreList)
482
+ lib = lib.library
483
+ }
484
+ if (!isObject(lib)) continue
485
+ const item = { entry, lib, ignore, index: i }
486
+ if (isBaseLibraryKey(entryLibraryKey(entry, lib))) bases.push(item)
487
+ else linked.push(item)
488
+ }
489
+ return { linked, bases }
490
+ }
491
+
492
+ /**
493
+ * Run `mergeOne(item)` for every library in merge order and rank the default
494
+ * font family claims — one rule for every caller:
495
+ * 1. the consumer's own claim, read before any library lands (afterwards a
496
+ * library's families sit in the consumer's own bags and the two can no
497
+ * longer be told apart);
498
+ * 2. else the linked libraries' claims, read after they land and BEFORE the
499
+ * base does (afterwards the base's flag can sit on a linked family of the
500
+ * same name, filled in by `deepDefaults`);
501
+ * 3. else the base's claim stands.
502
+ * Merging the base last is not enough for the claim: scratch points
503
+ * `fontFamily.default` at the LAST flagged family it reads, so the base's
504
+ * family, now read last, would win it. Returns the claims every other flag
505
+ * yields to (see `yieldLibraryDefaultFonts`), or null when nothing yields.
506
+ */
507
+ const mergeInPrecedenceOrder = (libraries, readDesignSystem, mergeOne) => {
508
+ const ownClaims = defaultFontClaims(readDesignSystem())
509
+ const { linked, bases } = inMergeOrder(libraries)
510
+ for (const item of linked) mergeOne(item)
511
+ const linkedClaims = !ownClaims.size && bases.length
512
+ ? defaultFontClaims(readDesignSystem())
513
+ : null
514
+ for (const item of bases) mergeOne(item)
515
+ if (ownClaims.size) return ownClaims
516
+ return linkedClaims && linkedClaims.size ? linkedClaims : null
517
+ }
518
+
417
519
  /**
418
520
  * Merge an array of shared library objects into a context.
419
521
  * - designSystem: deep defaults (non-destructive recursive)
@@ -423,8 +525,18 @@ const libraryLabel = (entry, lib, index) => {
423
525
  * - new top-level keys: copy from library
424
526
  * - `app` NEVER merges — a library's root definition is not consumer
425
527
  * content (see the unconditional exclusion in `mergeOneLibrary`)
426
- * - a font family the consumer flags `isDefault` stays the default — every
427
- * library's own claim yields (see `yieldLibraryDefaultFonts`)
528
+ *
529
+ * PRECEDENCE, highest first — the add-missing merge is first-wins, so this is
530
+ * the merge order:
531
+ * 1. the consumer's own context;
532
+ * 2. the libraries the project linked, in declaration order (an earlier entry
533
+ * outranks a later one);
534
+ * 3. the base library, system/default, wherever it sits in `libraries` (see
535
+ * `isBaseLibraryKey`);
536
+ * 4. after this merge, the framework defaults (`@symbo.ls/default-config`).
537
+ * The default font family claim follows the same ranking — a font family the
538
+ * consumer flags `isDefault` stays the default, else a linked library's claim
539
+ * outranks the base's (see `mergeInPrecedenceOrder`).
428
540
  *
429
541
  * Entries may be a bare library context, or a wrapped `{ library, ignoreList }`
430
542
  * (see `sharedLibrary`). `ignoreList` names paths to skip while merging that
@@ -432,21 +544,50 @@ const libraryLabel = (entry, lib, index) => {
432
544
  */
433
545
  export const mergeSharedLibraries = (context, libraries) => {
434
546
  if (!libraries || !libraries.length) return
435
- // Read BEFORE any library lands: afterwards a library's families sit in the
436
- // consumer's own bags and the two can no longer be told apart.
437
- const ownDefaultFonts = defaultFontClaims(context.designSystem)
438
- for (let i = 0; i < libraries.length; i++) {
439
- const entry = libraries[i]
440
- let sharedLib = entry
441
- let ignore = EMPTY_IGNORE
442
- if (isWrappedLibrary(sharedLib)) {
443
- ignore = normalizeIgnoreList(sharedLib.ignoreList)
444
- sharedLib = sharedLib.library
445
- }
446
- if (!isObject(sharedLib)) continue
447
- mergeOneLibrary(context, sharedLib, ignore, libraryLabel(entry, sharedLib, i))
547
+ const ownDesignSystem = context.designSystem
548
+ const claims = mergeInPrecedenceOrder(
549
+ libraries,
550
+ () => context.designSystem,
551
+ ({ entry, lib, ignore, index }) =>
552
+ mergeOneLibrary(context, lib, ignore, libraryLabel(entry, lib, index))
553
+ )
554
+ if (!claims) return
555
+ // A consumer with no design system of its own holds the first library's
556
+ // object here (the wholesale-copy branch adopts it): copy it before a bag
557
+ // changes, so the yield never writes into a library.
558
+ if (context.designSystem !== ownDesignSystem) {
559
+ context.designSystem = { ...context.designSystem }
448
560
  }
449
- if (ownDefaultFonts.size) yieldLibraryDefaultFonts(context.designSystem, ownDefaultFonts)
561
+ yieldLibraryDefaultFonts(context.designSystem, claims)
562
+ }
563
+
564
+ /**
565
+ * Merge only the shared libraries' DESIGN SYSTEMS into `designSystem`, in
566
+ * place, with the precedence and the default font family rule of
567
+ * `mergeSharedLibraries`. For a caller that rebuilds the design system alone —
568
+ * the livesync re-init (@symbo.ls/sync `buildReinitDesignSystem`) — so a
569
+ * rebuilt page ranks its libraries exactly as its boot did.
570
+ *
571
+ * `fill(target, source, skip, prefix)` merges one library (default
572
+ * `deepDefaults`); a copying fill keeps the libraries untouched across
573
+ * repeated rebuilds. `skip` carries the consumer's `ignoreList` and the
574
+ * library's own `sharedLibIgnore`, as in `mergeSharedLibraries`.
575
+ */
576
+ export const mergeSharedLibraryDesignSystems = (designSystem, libraries, fill = deepDefaults) => {
577
+ if (!isObject(designSystem) || !Array.isArray(libraries) || !libraries.length) return designSystem
578
+ const claims = mergeInPrecedenceOrder(
579
+ libraries,
580
+ () => designSystem,
581
+ ({ lib, ignore }) => {
582
+ const source = lib.designSystem
583
+ if (!source || typeof source !== 'object') return
584
+ const skip = librarySkip(lib, ignore)
585
+ if (skip.has('designSystem')) return
586
+ fill(designSystem, source, skip, 'designSystem')
587
+ }
588
+ )
589
+ if (claims) yieldLibraryDefaultFonts(designSystem, claims)
590
+ return designSystem
450
591
  }
451
592
 
452
593
  /**