@mapled/vanilla 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  <html lang="en">
14
14
  <head>
15
15
  <title data-mapled-bind="home.headline">Studio Nord</title>
16
- <script src="https://cdn.jsdelivr.net/npm/@mapled/vanilla@0.1.0/dist/mapled.js" data-mapled-key="mk_live_…" defer></script>
16
+ <script src="https://cdn.jsdelivr.net/npm/@mapled/vanilla@0.1.1/dist/mapled.js" data-mapled-key="mk_live_…" defer></script>
17
17
  </head>
18
18
  <body>
19
19
  <h1 data-mapled-bind="home.headline">Websites, built by hand</h1>
@@ -113,7 +113,7 @@ The key is the project's **delivery key** (Mapled: Integrations → Your site).
113
113
  | `missing` | No such single, record or collection in the release — or nothing in the address to find a record by | The HTML you wrote |
114
114
  | `empty` | The record is there, a value at this path isn't: an editor left the field empty — or the key is misspelled | Nothing: the text is emptied, a picture is hidden, an attribute is removed (`alt` becomes `""`) |
115
115
  | `failed` | The read didn't come back | The HTML you wrote |
116
- | `unsafe-url` | An address that isn't `http:`, `https:` — or `mailto:`, `tel:` in a link — or that carries credentials | The HTML you wrote |
116
+ | `unsafe-url` | An address that isn't `http:`, `https:` — or `mailto:`, `tel:` in a link — or that carries credentials; a value that can't go into a link template | The HTML you wrote |
117
117
  | `type` | A value that has no text: a group bound as text, a word where a date goes | The HTML you wrote |
118
118
  | `refused-element` | `<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<base>`, `<link>`, `<meta>`, `<template>`, `<noscript>` are never written into | The HTML you wrote |
119
119
  | `unsupported` | An attribute Mapled doesn't read — `data-mapled-bind-style`, a misspelled name — or a list without a `<template>` | The HTML you wrote |
@@ -129,7 +129,7 @@ The key is the project's **delivery key** (Mapled: Integrations → Your site).
129
129
  </script>
130
130
  ```
131
131
 
132
- `state` is `ready`, `unpublished` (nothing is published yet) or `fallback` (Mapled couldn't be reached); the same word is on `<html data-mapled-state="…">`, `loading` before the first fill — a hook for CSS, set by the script only, so a page whose script never loaded hides nothing. `mapled:update` follows every later fill. In the console, `Mapled.page.report` is the last report and `Mapled.page.refresh()` fills again — call it after your own script adds elements with attributes. Every fill starts from the HTML you wrote, so a value that stops fitting gives its place back to your fallback, not to the previous release.
132
+ `state` is `ready`, `unpublished` (nothing is published yet) or `fallback` (Mapled couldn't be reached — or preview just ended and what is published is on its way); the same word is on `<html data-mapled-state="…">`, `loading` before the first fill — a hook for CSS, set by the script only, so a page whose script never loaded hides nothing. `mapled:update` follows every later fill. In the console, `Mapled.page.report` is the last report and `Mapled.page.refresh()` fills again — call it after your own script adds elements with attributes. Every fill starts from the HTML you wrote, so a value that stops fitting gives its place back to your fallback, not to the previous release.
133
133
 
134
134
  ## Preview
135
135
 
package/dist/mapled.js CHANGED
@@ -1,18 +1,18 @@
1
- /*! @mapled/vanilla 0.1.0 | MIT | https://mapled.io */
2
- "use strict";(()=>{var pt=Object.defineProperty;var mt=(e,t,n)=>t in e?pt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ue=(e,t,n)=>mt(e,typeof t!="symbol"?t+"":t,n);var ce="mapled-preview",Q="mapled:preview",gt=/^mpv_[A-Za-z0-9]{16,96}$/,Le=/^mps_[A-Za-z0-9]{16,96}$/,Me=new WeakMap,ht=4e3;function Ue(){if(typeof window>"u"||typeof document>"u")return null;try{let e=window.sessionStorage,t=Me.get(window);return t||Me.set(window,t={memory:null,exchanging:null}),{location:window.location,history:window.history,sessionStorage:e,page:t}}catch{return null}}function yt(e){try{let t=e.getItem(Q);if(!t)return null;let n=JSON.parse(t),r=typeof n?.expiresAt=="string"?Date.parse(n.expiresAt):NaN;return typeof n?.draftToken!="string"||!Le.test(n.draftToken)||!(r>Date.now())?(e.removeItem(Q),null):{draftToken:n.draftToken,expiresAt:n.expiresAt}}catch{return null}}function F(e){let t=yt(e.sessionStorage);if(t)return t;let n=e.page.memory;return n&&Date.parse(n.expiresAt)>Date.now()?n:(e.page.memory=null,null)}function ee(){let e=Ue();if(e){e.page.memory=null;try{e.sessionStorage.removeItem(Q)}catch{}}}function Ne(e={}){let t=Ue();if(!t)return Promise.resolve(null);let n;try{n=new URL(t.location.href)}catch{return Promise.resolve(F(t))}let r=n.searchParams.get(ce);if(r===null)return t.page.exchanging?t.page.exchanging.done:Promise.resolve(F(t));n.searchParams.delete(ce);try{t.history.replaceState(t.history.state,"",`${n.pathname}${n.search}${n.hash}`)}catch{}if(!gt.test(r))return Promise.resolve(F(t));if(t.page.exchanging?.token===r)return t.page.exchanging.done;let s=(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,""),l=(e.appUrl??"https://app.mapled.io").replace(/\/+$/,""),u=e.fetch??fetch,i=(async()=>{try{let o=await u(`${s}/v1/delivery/preview/exchange`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({token:r}),cache:"no-store"});if(o.ok){let a=await o.json();if(typeof a.draftToken!="string"||typeof a.expiresAt!="string"||!Le.test(a.draftToken))return F(t);let d={draftToken:a.draftToken,expiresAt:a.expiresAt};t.page.memory=d;try{t.sessionStorage.setItem(Q,JSON.stringify(d))}catch{}return d}if(o.status===401){let a=await o.json().catch(()=>null),d=a?.error?.projectId;if(a?.error?.code==="PREVIEW_EXPIRED"&&typeof d=="string"&&/^[0-9a-f-]{8,64}$/i.test(d))return t.location.assign(`${l}/preview/expired?project=${encodeURIComponent(d)}`),await new Promise(m=>setTimeout(m,ht)),F(t)}return F(t)}catch{return F(t)}})(),f={token:r,done:i};return t.page.exchanging=f,i.then(()=>{t.page.exchanging===f&&(t.page.exchanging=null)}),i}async function Ie(e){return(await Ne(e))?.draftToken??null}function bt(e){if(!e||typeof e!="object")return;let{release:t,publishedAt:n}=e;if(t===null)return null;if(!(!Number.isInteger(t)||t<1||typeof n!="string"))return{release:t,publishedAt:n}}function Fe(e){let t=typeof e.key=="string"&&e.key.length>0;if(!t&&!e.endpoint)throw new Error("Mapled: watchRelease needs an endpoint or a delivery key.");let n=t?`${(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,"")}/v1/delivery/release`:e.endpoint,r=t?{accept:"application/json","x-mapled-key":e.key}:{accept:"application/json"},s=(t?Math.max(15,e.interval??60):Math.max(2,e.interval??10))*1e3,l=e.fetch??fetch,u=typeof document>"u"?null:document,i,f=0,o=!1,a,d=null,m=()=>!u||u.visibilityState!=="hidden",w=()=>{o||!m()||(a=setTimeout(v,Math.min(s*2**f,3e5)))};async function v(){if(o||d)return;let O=new AbortController;d=O;let T=null;try{let M=await l(n,{cache:"no-cache",headers:r,signal:O.signal}),$=M.ok?bt(await M.json()):void 0;if(o)return;$===void 0?f+=1:(f=0,i===void 0?i=$?$.release:null:$&&$.release>(i??0)&&(T={next:$,previous:i},i=$.release))}catch{if(o)return;f+=1}finally{d===O&&(d=null)}w(),T&&e.onPublish(T.next,T.previous)}let x=()=>{clearTimeout(a),m()&&v()};return u?.addEventListener("visibilitychange",x),m()&&v(),()=>{o=!0,clearTimeout(a),d?.abort(),u?.removeEventListener("visibilitychange",x)}}function De(e){let t={};return e.forEach((n,r)=>{typeof n!="string"||r in t||(t[r]=n)}),t}async function de(e,t,n){if(!n?.key)throw new Error("Mapled: a delivery key is required.");let r=(n.apiUrl??"https://api.mapled.io").replace(/\/+$/,""),s=typeof HTMLFormElement<"u"&&t instanceof HTMLFormElement?De(new FormData(t)):typeof FormData<"u"&&t instanceof FormData?De(t):{...t},l=n.page??(typeof window<"u"&&typeof document<"u"?window.location.pathname:void 0),u={...s};n.consent&&(u._consent=n.consent),l&&u._page===void 0&&(u._page=l),n.test&&(u._test=!0);let i;try{i=await(n.fetch??fetch)(`${r}/v1/delivery/forms/${encodeURIComponent(e)}`,{method:"POST",headers:{"content-type":"application/json","x-mapled-key":n.key},body:JSON.stringify(u)})}catch{return{ok:!1,status:0,code:"NETWORK",message:"Mapled couldn't be reached. Try again in a minute."}}if(i.ok)return{ok:!0};let f=`The submission wasn't accepted (${i.status}).`,o;try{let a=await i.json();a.error?.message&&(f=a.error.message),typeof a.error?.code=="string"&&(o=a.error.code)}catch{}return{ok:!1,status:i.status,code:o,message:f}}var fe=/^[a-z0-9][a-z0-9-]{0,63}$/,Ke=new Set;function wt(e){if(typeof process<"u")return;let t=e?.aliases;if(!(!t||typeof t!="object")){for(let[n,r]of Object.entries(t))if(!(!r||typeof r!="object"||!fe.test(n)))for(let[s,l]of Object.entries(r)){if(typeof l!="string"||!fe.test(s)||!fe.test(l))continue;let u=`${n}.${s}`;Ke.has(u)||(Ke.add(u),console.warn(`[mapled] \u201C${s}\u201D in \u201C${n}\u201D was renamed to \u201C${l}\u201D. The old key keeps working until its alias is removed in Mapled \u2014 use \u201C${l}\u201D instead.`))}}}function Be(e,t={}){let n=(t.apiUrl??"https://api.mapled.io").replace(/\/+$/,""),r=new URLSearchParams;t.width&&r.set("w",String(t.width)),t.height&&r.set("h",String(t.height)),t.fit&&r.set("fit",t.fit),t.format&&r.set("fmt",t.format),t.quality&&r.set("q",String(t.quality));let s=r.toString();return`${n}/files/${encodeURIComponent(e)}${s?`?${s}`:""}`}var D=class extends Error{constructor(n,r,s){super(r);ue(this,"status");ue(this,"code");this.name="MapledError",this.status=n,this.code=s}},_e=e=>Number.isInteger(e)&&e>=1,je=()=>new Error("Mapled: release must be a positive whole number.");function qe(e){let t=(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,"");if(!e.key)throw new Error("Mapled: a delivery key is required.");if(e.release!==void 0&&!_e(e.release))throw je();let n=(o,a)=>(e.fetch??fetch)(o,a);async function r(){return e.draft===null?null:typeof e.draft=="string"?e.draft||null:typeof e.draft=="function"?await e.draft()||null:Ie({apiUrl:t,appUrl:e.appUrl,fetch:e.fetch})}async function s(o){let a=`Mapled request failed (${o.status}).`,d;try{let m=await o.json();m.error?.message&&(a=m.error.message),typeof m.error?.code=="string"&&(d=m.error.code)}catch{}return new D(o.status,a,d)}async function l(o,a,d){let m=await r(),w=d.release??e.release;if(w!==void 0&&!_e(w))throw je();w!==void 0&&!m&&a.set("release",String(w));let v=a.toString(),x=await n(`${t}${o}${v?`?${v}`:""}`,{headers:m?{"x-mapled-key":e.key,"x-mapled-draft":m}:{"x-mapled-key":e.key},...m?{cache:"no-store"}:{},...d.signal?{signal:d.signal}:{}});if(!x.ok)throw await s(x);let O=await x.json();return wt(O),O}let u=(o,a)=>(a.expand?.length&&o.set("expand",a.expand.join(",")),a.fields?.length&&o.set("fields",a.fields.join(",")),o),i=async(o,a)=>{try{return(await l(o,u(new URLSearchParams,a),a)).record}catch(d){if(d instanceof D&&d.status===404&&d.code!=="RELEASE_NOT_FOUND")return null;throw d}};return{async getRecords(o,a={}){let d=new URLSearchParams;for(let[m,w]of Object.entries(a.filter??{}))if(w!==null&&typeof w=="object")for(let[v,x]of Object.entries(w))x!==void 0&&d.set(`filter[${m}][${v}]`,Array.isArray(x)?x.join(","):String(x));else d.set(`filter[${m}]`,String(w));return a.sort&&d.set("sort",a.sort),a.limit!==void 0&&d.set("limit",String(a.limit)),a.offset!==void 0&&d.set("offset",String(a.offset)),u(d,a),l(`/v1/delivery/collections/${encodeURIComponent(o)}/records`,d,a)},getRecord(o,a,d={}){return i(`/v1/delivery/collections/${encodeURIComponent(o)}/records/${encodeURIComponent(a)}`,d)},getRecordBySlug(o,a,d={}){return i(`/v1/delivery/collections/${encodeURIComponent(o)}/records/by-slug/${encodeURIComponent(a)}`,d)},getSingle(o,a={}){return i(`/v1/delivery/singles/${encodeURIComponent(o)}`,a)},async isPreview(){return await r()!==null},watch(o,a={}){return Fe({key:e.key,apiUrl:t,interval:a.interval,onPublish:o,fetch:e.fetch})},async getRelease(o={}){let a=await n(`${t}/v1/delivery/release`,{headers:{"x-mapled-key":e.key},cache:"no-cache",...o.signal?{signal:o.signal}:{}});if(!a.ok)throw await s(a);let d=await a.json();return d.release===null||d.publishedAt===null?null:{release:d.release,publishedAt:d.publishedAt}}}}var kt=/^[a-z0-9][a-z0-9_-]{0,63}$/;function j(e){if(typeof e!="string")return null;let t=e.trim().split(".");if(t.length>8)return null;for(let n of t)if(!kt.test(n))return null;return t}var te=(e,t)=>e!==null&&typeof e=="object"&&!Array.isArray(e)&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0;function pe(e,t){let n=e.data,r=e.expanded;for(let s=0;s<t.length;s++){let l=t[s],u=s<t.length-1?te(r,l):void 0;if(u!==void 0){if(u===null||Array.isArray(u))return;n=te(u,"data"),r=te(u,"expanded");continue}if(n=te(n,l),r=void 0,n===void 0)return}return n}var B=e=>e==null||e===""||Array.isArray(e)&&e.length===0;function me(e){return typeof e=="string"?e:typeof e=="number"&&Number.isFinite(e)?String(e):typeof e=="boolean"?e?"true":"false":Array.isArray(e)&&e.every(t=>typeof t=="string"||typeof t=="number")?e.join(", "):null}var St=new Set(["http:","https:","mailto:","tel:"]),Rt=new Set(["http:","https:"]),At=2048;function N(e,t,n){if(typeof e!="string"||e.length>At)return null;let r;try{r=new URL(e,t)}catch{return null}return!(n==="link"?St:Rt).has(r.protocol)||r.username!==""||r.password!==""?null:r.href}var vt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,ze=e=>typeof e=="string"&&vt.test(e);function He(e,t,n){let r=[],s=e.replace(/\{([^{}]*)\}/g,(u,i)=>{let f=j(i);if(!f)return r.push({ok:!1,reason:"bad-path",path:i.trim().slice(0,80)}),"";let o=n(f);return typeof o!="string"&&typeof o!="number"||o===""?(r.push({ok:!1,reason:"empty",path:f.join(".")}),""):encodeURIComponent(String(o))});if(r[0])return r[0];let l=N(s,t,"link");return l===null?{ok:!1,reason:"unsafe-url",path:e.slice(0,80)}:{ok:!0,url:l}}var Tt=1e5,Ve=8,Ge=2048,Et="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",We={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:"\xA0",copy:"\xA9",reg:"\xAE",trade:"\u2122",mdash:"\u2014",ndash:"\u2013",hellip:"\u2026",laquo:"\xAB",raquo:"\xBB"};function Xe(e,t,n){let r=t.createDocumentFragment();if(typeof e!="string"||e==="")return r;let s=e.replace(/\r\n?/g,`
3
- `).replace(/\t/g," ").replace(/\u0000/g,"\uFFFD"),l={doc:t,base:n};if(s.length>Tt){for(let u of s.split(/\n{2,}/))u.trim()!==""&&(P(l,"p",r).textContent=u.trim());return r}return ke(l,s.split(`
4
- `),r,0),r}function P(e,t,n){let r=e.doc.createElement(t);return n.appendChild(r),r}var ge=e=>e.trim()==="",z=e=>e.length-e.trimStart().length;function Ze(e){let t=z(e);if(t>3)return null;let n=0;for(;n<7&&e[t+n]==="#";)n++;if(n===0||n>6)return null;let r=e[t+n];if(r!==void 0&&r!==" ")return null;let s=e.slice(t+n).trim(),l=s.length;for(;l>0&&s[l-1]==="#";)l--;return l<s.length&&(l===0||s[l-1]===" ")&&(s=s.slice(0,l).trim()),{level:n,text:s}}function we(e){if(z(e)>3)return!1;let t=e.replace(/ /g,""),n=t[0];if(t.length<3||n!=="-"&&n!=="*"&&n!=="_")return!1;for(let r of t)if(r!==n)return!1;return!0}function he(e){let t=/^ {0,3}(`{3,}|~{3,})/.exec(e);if(!t)return null;let n=t[1][0];return n==="`"&&e.slice(t[0].length).includes("`")?null:{mark:n,size:t[1].length}}function q(e){let t=/^( {0,3})([-*+]|\d{1,9}[.)])( +|$)/.exec(e);if(!t)return null;let n=t[2],r=t[3].length,s=n.length>1||/\d/.test(n);return{indent:t[1].length,width:n.length+(r>=1&&r<=4?r:1),ordered:s,start:s?parseInt(n,10):1,rest:e.slice(t[0].length)}}var ye=e=>/^ {0,3}>/.test(e);function xt(e){if(Ze(e)!==null||he(e)!==null||ye(e)||we(e))return!0;let t=q(e);return t!==null&&t.rest!==""&&(!t.ordered||t.start===1)}function ke(e,t,n,r){if(r>=Ve){let l=t.join(`
5
- `).trim();l!==""&&(P(e,"p",n).textContent=l);return}let s=0;for(;s<t.length;){let l=t[s];if(ge(l)){s++;continue}let u=he(l);if(u){let a=[],d=z(l);for(s++;s<t.length;){let m=t[s],w=he(m);if(w&&w.mark===u.mark&&w.size>=u.size&&m.trim().length===w.size)break;a.push(m.slice(Math.min(d,z(m)))),s++}s++,P(e,"code",P(e,"pre",n)).textContent=a.length>0?`${a.join(`
1
+ /*! @mapled/vanilla 0.1.1 | MIT | https://mapled.io */
2
+ "use strict";(()=>{var $t=Object.defineProperty;var Ct=(e,t,n)=>t in e?$t(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var me=(e,t,n)=>Ct(e,typeof t!="symbol"?t+"":t,n);var ge="mapled-preview",ne="mapled:preview",Lt=/^mpv_[A-Za-z0-9]{16,96}$/,Ge=/^mps_[A-Za-z0-9]{16,96}$/,Xe=new WeakMap,Ut=4e3;function he(){if(typeof window>"u"||typeof document>"u")return null;try{let e=window.sessionStorage,t=Xe.get(window);return t||Xe.set(window,t={memory:null,exchanging:null,epoch:0}),{location:window.location,history:window.history,sessionStorage:e,page:t}}catch{return null}}function Nt(e){try{let t=e.getItem(ne);if(!t)return null;let n=JSON.parse(t),r=typeof n?.expiresAt=="string"?Date.parse(n.expiresAt):NaN;return typeof n?.draftToken!="string"||!Ge.test(n.draftToken)||!(r>Date.now())?(e.removeItem(ne),null):{draftToken:n.draftToken,expiresAt:n.expiresAt}}catch{return null}}function D(e){let t=Nt(e.sessionStorage);if(t)return t;let n=e.page.memory;return n&&Date.parse(n.expiresAt)>Date.now()?n:(e.page.memory=null,null)}function _(){let e=he();return e?D(e):null}function Ve(e){let t;try{t=new URL(e.location.href)}catch{return null}let n=t.searchParams.get(ge);if(n===null)return null;t.searchParams.delete(ge);try{e.history.replaceState(e.history.state,"",`${t.pathname}${t.search}${t.hash}`)}catch{}return n}function ye(){let e=he();if(e){e.page.memory=null,e.page.epoch++,e.page.exchanging=null,Ve(e);try{e.sessionStorage.removeItem(ne)}catch{}}}function Ze(e={}){let t=he();if(!t)return Promise.resolve(null);let n=Ve(t);if(n===null)return t.page.exchanging?t.page.exchanging.done:Promise.resolve(D(t));if(!Lt.test(n))return Promise.resolve(D(t));if(t.page.exchanging?.token===n)return t.page.exchanging.done;let r=(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,""),s=(e.appUrl??"https://app.mapled.io").replace(/\/+$/,""),l=e.fetch??fetch,c=++t.page.epoch,a=(async()=>{try{let o=await l(`${r}/v1/delivery/preview/exchange`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({token:n}),cache:"no-store"});if(o.ok){let i=await o.json();if(typeof i.draftToken!="string"||typeof i.expiresAt!="string"||!Ge.test(i.draftToken)||!(Date.parse(i.expiresAt)>Date.now())||t.page.epoch!==c)return D(t);let d={draftToken:i.draftToken,expiresAt:i.expiresAt};t.page.memory=d;try{t.sessionStorage.setItem(ne,JSON.stringify(d))}catch{}return d}if(o.status===401&&t.page.epoch===c){let i=await o.json().catch(()=>null),d=i?.error?.projectId;if(t.page.epoch===c&&i?.error?.code==="PREVIEW_EXPIRED"&&typeof d=="string"&&/^[0-9a-f-]{8,64}$/i.test(d))return t.location.assign(`${s}/preview/expired?project=${encodeURIComponent(d)}`),await new Promise(p=>setTimeout(p,Ut)),D(t)}return D(t)}catch{return D(t)}})(),f={token:n,done:a};return t.page.exchanging=f,a.then(()=>{t.page.exchanging===f&&(t.page.exchanging=null)}),a}async function Ye(e){return(await Ze(e))?.draftToken??null}function be(e){if(!e||typeof e!="object")return;let{release:t,publishedAt:n}=e;if(t===null)return n===null?null:void 0;if(!(!Number.isInteger(t)||t<1||typeof n!="string"))return{release:t,publishedAt:n}}function Je(e){let t=typeof e.key=="string"&&e.key.length>0;if(!t&&!e.endpoint)throw new Error("Mapled: watchRelease needs an endpoint or a delivery key.");let n=t?`${(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,"")}/v1/delivery/release`:e.endpoint,r=t?{accept:"application/json","x-mapled-key":e.key}:{accept:"application/json"},s=(t?Math.max(15,e.interval??60):Math.max(2,e.interval??10))*1e3,l=e.fetch??fetch,c=typeof document>"u"?null:document,a,f=0,o=!1,i,d=null,p=()=>!c||c.visibilityState!=="hidden",k=()=>{o||!p()||(i=setTimeout(T,Math.min(s*2**f,3e5)))};async function T(){if(o||d)return;let M=new AbortController;d=M;let S=null;try{let C=await l(n,{cache:"no-cache",headers:r,signal:M.signal}),O=C.ok?be(await C.json()):void 0;if(o)return;O===void 0?f+=1:(f=0,a===void 0?a=O?O.release:null:O&&O.release>(a??0)&&(S={next:O,previous:a},a=O.release))}catch{if(o)return;f+=1}finally{d===M&&(d=null)}k(),S&&e.onPublish(S.next,S.previous)}let x=()=>{clearTimeout(i),p()&&T()};return c?.addEventListener("visibilitychange",x),p()&&T(),()=>{o=!0,clearTimeout(i),d?.abort(),c?.removeEventListener("visibilitychange",x)}}function Qe(e){let t={};return e.forEach((n,r)=>{typeof n!="string"||r in t||(t[r]=n)}),t}async function we(e,t,n){if(!n?.key)throw new Error("Mapled: a delivery key is required.");let r=(n.apiUrl??"https://api.mapled.io").replace(/\/+$/,""),s=typeof HTMLFormElement<"u"&&t instanceof HTMLFormElement?Qe(new FormData(t)):typeof FormData<"u"&&t instanceof FormData?Qe(t):{...t},l=n.page??(typeof window<"u"&&typeof document<"u"?window.location.pathname:void 0),c={...s};n.consent&&(c._consent=n.consent),l&&c._page===void 0&&(c._page=l),n.test&&(c._test=!0);let a;try{a=await(n.fetch??fetch)(`${r}/v1/delivery/forms/${encodeURIComponent(e)}`,{method:"POST",headers:{"content-type":"application/json","x-mapled-key":n.key},body:JSON.stringify(c)})}catch{return{ok:!1,status:0,code:"NETWORK",message:"Mapled couldn't be reached. Try again in a minute."}}if(a.ok)return{ok:!0};let f=`The submission wasn't accepted (${a.status}).`,o;try{let i=await a.json();i.error?.message&&(f=i.error.message),typeof i.error?.code=="string"&&(o=i.error.code)}catch{}return{ok:!1,status:a.status,code:o,message:f}}var ke=/^[a-z0-9][a-z0-9-]{0,63}$/,et=new Set;function It(e){if(typeof process<"u")return;let t=e?.aliases;if(!(!t||typeof t!="object")){for(let[n,r]of Object.entries(t))if(!(!r||typeof r!="object"||!ke.test(n)))for(let[s,l]of Object.entries(r)){if(typeof l!="string"||!ke.test(s)||!ke.test(l))continue;let c=`${n}.${s}`;et.has(c)||(et.add(c),console.warn(`[mapled] \u201C${s}\u201D in \u201C${n}\u201D was renamed to \u201C${l}\u201D. The old key keeps working until its alias is removed in Mapled \u2014 use \u201C${l}\u201D instead.`))}}}function rt(e,t={}){let n=(t.apiUrl??"https://api.mapled.io").replace(/\/+$/,""),r=new URLSearchParams;t.width&&r.set("w",String(t.width)),t.height&&r.set("h",String(t.height)),t.fit&&r.set("fit",t.fit),t.format&&r.set("fmt",t.format),t.quality&&r.set("q",String(t.quality));let s=r.toString();return`${n}/files/${encodeURIComponent(e)}${s?`?${s}`:""}`}var j=class extends Error{constructor(n,r,s){super(r);me(this,"status");me(this,"code");this.name="MapledError",this.status=n,this.code=s}},tt=e=>Number.isInteger(e)&&e>=1,nt=()=>new Error("Mapled: release must be a positive whole number.");function st(e){let t=(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,"");if(!e.key)throw new Error("Mapled: a delivery key is required.");if(e.release!==void 0&&!tt(e.release))throw nt();let n=(o,i)=>(e.fetch??fetch)(o,i);async function r(){return e.draft===null?null:typeof e.draft=="string"?e.draft||null:typeof e.draft=="function"?await e.draft()||null:Ye({apiUrl:t,appUrl:e.appUrl,fetch:e.fetch})}async function s(o){let i=`Mapled request failed (${o.status}).`,d;try{let p=await o.json();p.error?.message&&(i=p.error.message),typeof p.error?.code=="string"&&(d=p.error.code)}catch{}return new j(o.status,i,d)}async function l(o,i,d){let p=await r(),k=d.release??e.release;if(k!==void 0&&!tt(k))throw nt();k!==void 0&&!p&&i.set("release",String(k));let T=i.toString(),x=await n(`${t}${o}${T?`?${T}`:""}`,{headers:p?{"x-mapled-key":e.key,"x-mapled-draft":p}:{"x-mapled-key":e.key},...p?{cache:"no-store"}:{},...d.signal?{signal:d.signal}:{}});if(!x.ok)throw await s(x);let M=await x.json();return It(M),M}let c=(o,i)=>(i.expand?.length&&o.set("expand",i.expand.join(",")),i.fields?.length&&o.set("fields",i.fields.join(",")),o),a=async(o,i)=>{try{return(await l(o,c(new URLSearchParams,i),i)).record}catch(d){if(d instanceof j&&d.status===404&&d.code!=="RELEASE_NOT_FOUND")return null;throw d}};return{async getRecords(o,i={}){let d=new URLSearchParams;for(let[p,k]of Object.entries(i.filter??{}))if(k!==null&&typeof k=="object")for(let[T,x]of Object.entries(k))x!==void 0&&d.set(`filter[${p}][${T}]`,Array.isArray(x)?x.join(","):String(x));else d.set(`filter[${p}]`,String(k));return i.sort&&d.set("sort",i.sort),i.limit!==void 0&&d.set("limit",String(i.limit)),i.offset!==void 0&&d.set("offset",String(i.offset)),c(d,i),l(`/v1/delivery/collections/${encodeURIComponent(o)}/records`,d,i)},getRecord(o,i,d={}){return a(`/v1/delivery/collections/${encodeURIComponent(o)}/records/${encodeURIComponent(i)}`,d)},getRecordBySlug(o,i,d={}){return a(`/v1/delivery/collections/${encodeURIComponent(o)}/records/by-slug/${encodeURIComponent(i)}`,d)},getSingle(o,i={}){return a(`/v1/delivery/singles/${encodeURIComponent(o)}`,i)},async isPreview(){return await r()!==null},watch(o,i={}){return Je({key:e.key,apiUrl:t,interval:i.interval,onPublish:o,fetch:e.fetch})},async getRelease(o={}){let i=await n(`${t}/v1/delivery/release`,{headers:{"x-mapled-key":e.key},cache:"no-cache",...o.signal?{signal:o.signal}:{}});if(!i.ok)throw await s(i);let d=be(await i.json());if(d===void 0)throw new Error("Mapled: the release pointer didn't come back as one \u2014 check the API origin.");return d}}}var Dt=/^[a-z0-9][a-z0-9_-]{0,63}$/;function H(e){if(typeof e!="string")return null;let t=e.trim().split(".");if(t.length>8)return null;for(let n of t)if(!Dt.test(n))return null;return t}var re=(e,t)=>e!==null&&typeof e=="object"&&!Array.isArray(e)&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0;function Se(e,t){let n=e.data,r=e.expanded;for(let s=0;s<t.length;s++){let l=t[s],c=s<t.length-1?re(r,l):void 0;if(c!==void 0){if(c===null||Array.isArray(c))return;n=re(c,"data"),r=re(c,"expanded");continue}if(n=re(n,l),r=void 0,n===void 0)return}return n}var W=e=>e==null||e===""||Array.isArray(e)&&e.length===0;function Ae(e){return typeof e=="string"?e:typeof e=="number"&&Number.isFinite(e)?String(e):typeof e=="boolean"?e?"true":"false":Array.isArray(e)&&e.every(t=>typeof t=="string"||typeof t=="number")?e.join(", "):null}var Ft=new Set(["http:","https:","mailto:","tel:"]),_t=new Set(["http:","https:"]),jt=2048;function F(e,t,n){if(typeof e!="string"||e.length>jt)return null;let r;try{r=new URL(e,t)}catch{return null}return!(n==="link"?Ft:_t).has(r.protocol)||r.username!==""||r.password!==""?null:r.href}var Kt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,ot=e=>typeof e=="string"&&Kt.test(e);function it(e,t,n){let r=[],s=e.replace(/\{([^{}]*)\}/g,(c,a)=>{let f=H(a);if(!f)return r.push({ok:!1,reason:"bad-path",path:a.trim().slice(0,80)}),"";let o=n(f);if(typeof o!="string"&&typeof o!="number"||o==="")return r.push({ok:!1,reason:"empty",path:f.join(".")}),"";try{return encodeURIComponent(String(o))}catch{return r.push({ok:!1,reason:"unsafe-url",path:f.join(".")}),""}});if(r[0])return r[0];let l=F(s,t,"link");return l===null?{ok:!1,reason:"unsafe-url",path:e.slice(0,80)}:{ok:!0,url:l}}var Bt=1e5,lt=8,ut=2048,qt="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",at={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:"\xA0",copy:"\xA9",reg:"\xAE",trade:"\u2122",mdash:"\u2014",ndash:"\u2013",hellip:"\u2026",laquo:"\xAB",raquo:"\xBB"};function ct(e,t,n){let r=t.createDocumentFragment();if(typeof e!="string"||e==="")return r;let s=e.replace(/\r\n?/g,`
3
+ `).replace(/\t/g," ").replace(/\u0000/g,"\uFFFD"),l={doc:t,base:n};if(s.length>Bt){for(let c of s.split(/\n{2,}/))c.trim()!==""&&(P(l,"p",r).textContent=c.trim());return r}return Pe(l,s.split(`
4
+ `),r,0),r}function P(e,t,n){let r=e.doc.createElement(t);return n.appendChild(r),r}var Re=e=>e.trim()==="",G=e=>e.length-e.trimStart().length;function dt(e){let t=G(e);if(t>3)return null;let n=0;for(;n<7&&e[t+n]==="#";)n++;if(n===0||n>6)return null;let r=e[t+n];if(r!==void 0&&r!==" ")return null;let s=e.slice(t+n).trim(),l=s.length;for(;l>0&&s[l-1]==="#";)l--;return l<s.length&&(l===0||s[l-1]===" ")&&(s=s.slice(0,l).trim()),{level:n,text:s}}function xe(e){if(G(e)>3)return!1;let t=e.replace(/ /g,""),n=t[0];if(t.length<3||n!=="-"&&n!=="*"&&n!=="_")return!1;for(let r of t)if(r!==n)return!1;return!0}function ve(e){let t=/^ {0,3}(`{3,}|~{3,})/.exec(e);if(!t)return null;let n=t[1][0];return n==="`"&&e.slice(t[0].length).includes("`")?null:{mark:n,size:t[1].length}}function X(e){let t=/^( {0,3})([-*+]|\d{1,9}[.)])( +|$)/.exec(e);if(!t)return null;let n=t[2],r=t[3].length,s=n.length>1||/\d/.test(n);return{indent:t[1].length,width:n.length+(r>=1&&r<=4?r:1),ordered:s,start:s?parseInt(n,10):1,rest:e.slice(t[0].length)}}var Te=e=>/^ {0,3}>/.test(e);function zt(e){if(dt(e)!==null||ve(e)!==null||Te(e)||xe(e))return!0;let t=X(e);return t!==null&&t.rest!==""&&(!t.ordered||t.start===1)}function Pe(e,t,n,r){if(r>=lt){let l=t.join(`
5
+ `).trim();l!==""&&(P(e,"p",n).textContent=l);return}let s=0;for(;s<t.length;){let l=t[s];if(Re(l)){s++;continue}let c=ve(l);if(c){let i=[],d=G(l);for(s++;s<t.length;){let p=t[s],k=ve(p);if(k&&k.mark===c.mark&&k.size>=c.size&&p.trim().length===k.size)break;i.push(p.slice(Math.min(d,G(p)))),s++}s++,P(e,"code",P(e,"pre",n)).textContent=i.length>0?`${i.join(`
6
6
  `)}
7
- `:"";continue}let i=Ze(l);if(i){re(e,i.text,P(e,`h${i.level}`,n),r),s++;continue}if(we(l)){P(e,"hr",n),s++;continue}if(ye(l)){let a=[];for(;s<t.length&&ye(t[s]);)a.push(t[s].replace(/^ {0,3}> ?/,"")),s++;ke(e,a,P(e,"blockquote",n),r+1);continue}let f=q(l);if(f){s=Pt(e,t,s,f,n,r);continue}let o=[l.trimStart()];for(s++;s<t.length&&!ge(t[s])&&!xt(t[s]);)o.push(t[s].trimStart()),s++;re(e,o.join(`
8
- `),P(e,"p",n),r)}}function Pt(e,t,n,r,s,l){let u=P(e,r.ordered?"ol":"ul",s);r.ordered&&r.start!==1&&u.setAttribute("start",String(r.start));let i=[],f=!1;for(;n<t.length;){let o=q(t[n]);if(!o||o.ordered!==r.ordered||o.indent!==r.indent||we(t[n]))break;let a=o.indent+o.width,d=[o.rest];n++;let m=!1;for(;n<t.length;){let w=t[n];if(ge(w)){m=!0,d.push(""),n++;continue}if(z(w)<a)break;m&&d.some(v=>v!=="")&&!q(w.slice(a))&&(f=!0),m=!1,d.push(w.slice(a)),n++}for(;d.length>0&&d[d.length-1]==="";)d.pop();if(m&&n<t.length){let w=q(t[n]);w&&w.ordered===r.ordered&&w.indent===r.indent&&(f=!0)}i.push({lines:d,el:P(e,"li",u)})}for(let o of i)if(ke(e,o.lines,o.el,l+1),!f){for(let a of Array.from(o.el.childNodes))if(a.nodeName==="P"){for(;a.firstChild;)o.el.insertBefore(a.firstChild,a);o.el.removeChild(a)}}return n}var Se=e=>e===void 0||e===" "||e===`
9
- `,Ye=e=>e!==void 0&&/[\p{L}\p{N}]/u.test(e);function ne(e,t,n,r,s=""){let l=Math.min(e.length,r);for(let u=n;u<l;u++){if(e[u]===t)return u;if(s.includes(e[u]))return-1}return-1}function H(e,t,n){let r=t;for(;e[r]===n;)r++;return r}function Je(e,t){if(e[t]==="\\")return t+2;if(e[t]==="`"){let n=H(e,t,"`"),r=Qe(e,n,n-t);return r===-1?n:r+(n-t)}return-1}function Qe(e,t,n){let r=e.indexOf("`",t);for(;r!==-1;){let s=H(e,r,"`");if(s-r===n)return r;r=e.indexOf("`",s)}return-1}function Ot(e,t,n){let r=n[0],s=t;for(;s<e.length;){let l=Je(e,s);if(l!==-1){s=l;continue}if(e[s]!==r){s++;continue}let u=H(e,s,r),i=u-s;if((n.length===1?i===1||i>=3:i>=n.length)&&s>t&&!Se(e[s-1])&&(r!=="_"||!Ye(e[u])))return u-n.length;s=u}return-1}function $t(e,t){let n=ne(e,";",t+1,t+34,`
10
- &`);if(n===-1)return null;let r=e.slice(t+1,n);if(r[0]==="#"){let l=r[1]==="x"||r[1]==="X",u=r.slice(l?2:1);if(!(l?/^[0-9a-fA-F]{1,6}$/:/^[0-9]{1,7}$/).test(u))return null;let i=parseInt(u,l?16:10);return{char:i>0&&i<=1114111&&!(i>=55296&&i<=57343)?String.fromCodePoint(i):"\uFFFD",end:n+1}}let s=Object.prototype.hasOwnProperty.call(We,r)?We[r]:void 0;return s===void 0?null:{char:s,end:n+1}}var et=e=>e.replace(/\\([!-/:-@[-`{-~])/g,"$1");function Ct(e,t){if(e[t]!=="(")return null;let n=Math.min(e.length,t+Ge+1024),r=t+1;for(;r<n&&Se(e[r])&&e[r]!==void 0;)r++;let s="";if(e[r]==="<"){let u=ne(e,">",r+1,n,`
11
- <`);if(u===-1)return null;s=e.slice(r+1,u),r=u+1}else{let u=r,i=0;for(;r<n;){let f=e[r];if(f==="\\"&&r+1<n){r+=2;continue}if(f===" "||f===`
12
- `)break;if(f==="("&&i++,f===")"){if(i===0)break;i--}r++}s=e.slice(u,r)}for(;r<n&&(e[r]===" "||e[r]===`
13
- `);)r++;let l=e[r];if(l==='"'||l==="'"||l==="("){let u=ne(e,l==="("?")":l,r+1,n);if(u===-1)return null;for(r=u+1;r<n&&(e[r]===" "||e[r]===`
14
- `);)r++}return e[r]!==")"?null:{address:et(s),end:r+1}}function be(e,t,n=!1){let r=t+1;for(;r<e.length;){let l=Je(e,r);if(l!==-1){r=l;continue}if(!n&&e[r]==="!"&&e[r+1]==="["){let u=be(e,r+1,!0);if(!u)return null;r=u.end;continue}if(e[r]==="[")return null;if(e[r]==="]")break;r++}if(r>=e.length)return null;let s=Ct(e,r+1);return s?{label:e.slice(t+1,r),address:s.address,end:s.end}:null}var Mt=/^(?:[a-z][a-z0-9+.-]{1,31}:[^\s<>]*|[^\s<>@]+@[^\s<>@]+\.[^\s<>@]+)$/i;function re(e,t,n,r){if(r>=Ve){n.appendChild(e.doc.createTextNode(t));return}let s="",l=()=>{s!==""&&n.appendChild(e.doc.createTextNode(s)),s=""},u=new Set,i=0;for(;i<t.length;){let f=t[i];if(f==="\\"){let o=t[i+1];if(o===`
15
- `)for(l(),P(e,"br",n),i+=2;t[i]===" ";)i++;else o!==void 0&&Et.includes(o)?(s+=o,i+=2):(s+=f,i++);continue}if(f===`
16
- `){let o=s.endsWith(" ");for(s=s.replace(/ +$/,""),o?(l(),P(e,"br",n)):s+=`
17
- `,i++;t[i]===" ";)i++;continue}if(f==="`"){let o=H(t,i,"`"),a=Qe(t,o,o-i);if(a===-1){s+=t.slice(i,o),i=o;continue}let d=t.slice(o,a).replace(/\n/g," ");d.length>1&&d.startsWith(" ")&&d.endsWith(" ")&&d.trim()!==""&&(d=d.slice(1,-1)),l(),P(e,"code",n).textContent=d,i=a+(o-i);continue}if(f==="!"&&t[i+1]==="["){let o=be(t,i+1);if(o){let a=et(o.label),d=N(o.address.trim(),e.base,"media");if(d===null)s+=a;else{l();let m=P(e,"img",n);m.setAttribute("src",d),m.setAttribute("alt",a),m.setAttribute("loading","lazy")}i=o.end;continue}}if(f==="["){let o=be(t,i);if(o){let a=N(o.address.trim(),e.base,"link");l();let d=a===null?n:P(e,"a",n);a!==null&&d.setAttribute("href",a),re(e,o.label,d,r+1),i=o.end;continue}}if(f==="<"){let o=ne(t,">",i+1,i+Ge,`
18
- <`),a=o===-1?null:t.slice(i+1,o);if(a!==null&&Mt.test(a)){let d=N(a.includes(":")?a:`mailto:${a}`,e.base,"link");if(d!==null){l();let m=P(e,"a",n);m.setAttribute("href",d),m.textContent=a,i=o+1;continue}}}if(f==="&"){let o=$t(t,i);if(o){s+=o.char,i=o.end;continue}}if(f==="*"||f==="_"||f==="~"){let o=H(t,i,f),a=o-i,d=!Se(t[o])&&(f!=="_"||!Ye(t[i-1])),m=f==="~"?a>=2?[["~~",["del"]]]:[]:[...a>=3?[[f.repeat(3),["em","strong"]]]:[],...a>=2?[[f.repeat(2),["strong"]]]:[],[f,["em"]]],w=!1;if(d)for(let[v,x]of m){if(u.has(v))continue;let O=i+v.length,T=Ot(t,O,v);if(T===-1){u.add(v);continue}if(T===O)continue;l();let M=n;for(let $ of x)M=P(e,$,M);re(e,t.slice(O,T),M,r+1),i=T+v.length,w=!0;break}w||(s+=t.slice(i,o),i=o);continue}s+=f,i++}l()}var Lt="http://www.w3.org/1999/xhtml",Ut=new Set(["script","style","iframe","frame","frameset","object","embed","applet","base","link","meta","template","noscript"]),se={href:{on:["a","area"],holds:"link"},src:{on:["img","video","audio","source"],holds:"media"},alt:{on:["img","area"],holds:"text"},title:{on:null,holds:"text"},"aria-label":{on:null,holds:"text"},placeholder:{on:["input","textarea"],holds:"text"},datetime:{on:["time","del","ins"],holds:"text"}},oe=e=>e.namespaceURI===Lt,W=e=>!Ut.has(e.localName.toLowerCase());function Re(e,t){if(!W(e))return"refused-element";let n=me(t);return n===null?"type":(e.textContent=n,null)}function tt(e,t,n){return!W(e)||!oe(e)?"refused-element":typeof t!="string"?"type":(e.replaceChildren(Xe(t,e.ownerDocument,n.base)),null)}function nt(e,t,n){return typeof e!="string"?null:ze(e)?Be(e,{...t.apiUrl?{apiUrl:t.apiUrl}:{},...n?{width:n}:{}}):N(e,t.base,"media")}function rt(e,t,n,r){if(!oe(e)||e.localName!=="img")return"refused-element";if(typeof t!="string")return"type";let s=nt(t,n,r);return s===null?"unsafe-url":(e.removeAttribute("srcset"),e.setAttribute("src",s),null)}function st(e,t,n,r,s){let l=t.toLowerCase(),u=Object.prototype.hasOwnProperty.call(se,l)?se[l]:void 0;if(!u)return"unsupported";if(!W(e)||!oe(e))return"refused-element";if(u.on!==null&&!u.on.includes(e.localName))return"unsupported";if(u.holds==="text"){let f=me(n);return f===null?"type":(e.setAttribute(l,f),null)}if(typeof n!="string")return"type";let i=u.holds==="media"?nt(n,r,e.localName==="img"?s:void 0):N(n,r.base,"link");return i===null?"unsafe-url":(e.setAttribute(l,i),null)}function ot(e,t){return!oe(e)||e.localName!=="a"&&e.localName!=="area"?"unsupported":(e.setAttribute("href",t),null)}function K(e,t){t?e.removeAttribute("hidden"):e.setAttribute("hidden","")}var it=["text","markdown","date","datetime","number"],Nt=/^\d{4}-\d{2}-\d{2}$/,It=/^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;function at(e,t,n){let r=n&&/^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$/.test(n)?n:void 0;try{if(t==="number"){let u=typeof e=="number"?e:typeof e=="string"&&e.trim()!==""?Number(e):NaN;return Number.isFinite(u)?new Intl.NumberFormat(r).format(u):null}if(typeof e!="string"||!It.test(e))return null;let s=new Date(e);if(Number.isNaN(s.getTime()))return null;let l=Nt.test(e);return new Intl.DateTimeFormat(r,{dateStyle:"long",...t==="datetime"&&!l?{timeStyle:"short"}:{},...l?{timeZone:"UTC"}:{}}).format(s)}catch{return null}}var S="data-mapled-",Ft=new Set(["bind","format","width","show","hide","link","list","each","record","slug","slug-param","sort","limit","filter","expand","empty","form","form-state","form-sent","form-failed","consent","end-preview","state","preview","key","api","live"]),ve=/^[a-z0-9][a-z0-9_-]{0,63}$/,Dt=/^mk_[A-Za-z0-9_]{8,128}$/,Kt=4;function U(e){let t=e.getAttribute("id");return`${e.localName}${t&&/^[\w-]{1,40}$/.test(t)?`#${t}`:""}`}var ae=e=>(e??"").split(",").map(t=>t.trim()).filter(t=>/^[a-z0-9][a-z0-9_.-]{0,127}$/.test(t)),lt=e=>Array.from(e.children).find(t=>t.localName==="template")??null;function Ae(e,t){let n=null,r=()=>n??(n={format:"text",attrs:[],expand:[]});for(let i of Array.from(e.attributes)){if(!i.name.startsWith(S))continue;let f=i.name.slice(S.length);if(f==="bind")r().bind=i.value;else if(f.startsWith("bind-")){let o=f.slice(5);Object.prototype.hasOwnProperty.call(se,o)?r().attrs.push([o,i.value]):t.push({path:i.value.slice(0,80),reason:"unsupported",on:`${U(e)}[${i.name.slice(0,60)}]`})}else f==="show"?r().show=i.value:f==="hide"?r().hide=i.value:f==="link"?r().link=i.value:Ft.has(f)||t.push({path:i.value.slice(0,80),reason:"unsupported",on:`${U(e)}[${i.name.slice(0,60)}]`})}if(!n)return null;let s=n,l=e.getAttribute(`${S}format`);l!==null&&(it.includes(l)?s.format=l:t.push({path:l.slice(0,80),reason:"bad-path",on:`${U(e)}[${S}format]`}));let u=parseInt(e.getAttribute(`${S}width`)??"",10);return u>=16&&u<=4096&&(s.width=u),s.expand=ae(e.getAttribute(`${S}expand`)),s}function _t(e,t){let n={},r=e.getAttribute(`${S}sort`);r!==null&&(/^-?[a-z0-9][a-z0-9_-]{0,63}$/.test(r.trim())?n.sort=r.trim():t.push({path:r.slice(0,80),reason:"bad-path",on:`${U(e)}[${S}sort]`}));let s=parseInt(e.getAttribute(`${S}limit`)??"",10);s>=1&&s<=100&&(n.limit=s);let l=e.getAttribute(`${S}filter`);if(l!==null)for(let i of l.split(";")){if(i.trim()==="")continue;let f=i.indexOf("="),o=f===-1?"":i.slice(0,f).trim(),a=f===-1?"":i.slice(f+1).trim();ve.test(o)&&a!==""&&a.length<=200?(n.filter??(n.filter={}))[o]=a:t.push({path:i.trim().slice(0,80),reason:"bad-path",on:`${U(e)}[${S}filter]`})}let u=ae(e.getAttribute(`${S}expand`));return u.length>0&&(n.expand=u),n}function ie(e,t){let n={bound:[],eaches:[],lists:[],records:[],issues:[]},r=s=>{if(s.hasAttributes()){let l=s.getAttribute(`${S}list`),u=s.getAttribute(`${S}record`),i=s.getAttribute(`${S}each`);if(l!==null||u!==null){let o=(l??u??"").trim();if(!t)n.issues.push({path:o.slice(0,80),reason:"unsupported",on:U(s)});else if(!ve.test(o))n.issues.push({path:o.slice(0,80),reason:"bad-path",on:U(s)});else if(l!==null)n.lists.push({el:s,collection:o,options:_t(s,n.issues)});else{let a=s.getAttribute(`${S}slug-param`),d=s.getAttribute(`${S}slug`)??(a===null?null:new URLSearchParams(s.ownerDocument.location?.search??"").get(a)),m=ie(s,!0);for(let v of m.records)n.issues.push({path:v.collection,reason:"unsupported",on:U(v.el)});n.lists.push(...m.lists),n.issues.push(...m.issues);let w=Ae(s,n.issues);w&&m.bound.unshift({el:s,d:w}),n.records.push({el:s,collection:o,slug:d!==null&&d.trim()!==""&&d.length<=200?d.trim():null,expand:ae(s.getAttribute(`${S}expand`)),block:{...m,lists:[],records:[],issues:[]}})}return}if(i!==null){n.eaches.push({el:s,path:i});return}let f=Ae(s,n.issues);f&&n.bound.push({el:s,d:f})}for(let l of Array.from(s.children))r(l)};for(let s of Array.from(e.children))r(s);return n}function ut(e){let t=new Map,n=(r,s=[])=>{let l=j(r)?.[0];if(!l)return;let u=t.get(l)??new Set;for(let i of s)u.add(i);t.set(l,u)};for(let{d:r}of e.bound){n(r.bind,r.expand);for(let[,s]of r.attrs)n(s,r.expand);n(r.show,r.expand),n(r.hide,r.expand);for(let s of(r.link??"").matchAll(/\{([^{}]*)\}/g))n(s[1],r.expand)}for(let r of e.eaches)n(r.path,ae(r.el.getAttribute(`${S}expand`)));return t}function V(e,t){let n=j(t);if(!n)return{status:"bad-path"};if(e.kind==="record")return{status:"value",value:pe(e.source,n)};if(n.length<2)return{status:"bad-path"};let r=e.singles.get(n[0]);return!r||r.status!=="ok"?{status:r?.status==="failed"?"failed":"missing"}:{status:"value",value:pe(r.value,n.slice(1))}}function Te(e){if(typeof e?.key!="string"||!Dt.test(e.key))throw new Error("Mapled: data-mapled-key takes the delivery key (mk_\u2026) \u2014 the one key that is safe in a page. A server key or a secret never goes into HTML.");if(typeof document>"u")throw new Error("Mapled: @mapled/vanilla fills a page \u2014 it runs in a browser. On a server read with @mapled/client.");let t=e.root??document.documentElement,n=t.ownerDocument,r=qe({key:e.key,apiUrl:e.apiUrl,appUrl:e.appUrl,fetch:e.fetch}),s={apiUrl:e.apiUrl,base:n.baseURI},l=new Map,u=c=>{let p=l.get(c);return p||l.set(c,p={attrs:new Map}),p},i=c=>{let p=u(c);p.nodes??(p.nodes=Array.from(c.childNodes))},f=(c,p)=>{let R=u(c);R.attrs.has(p)||R.attrs.set(p,c.getAttribute(p))},o=()=>{for(let[c,p]of l){p.nodes&&c.replaceChildren(...p.nodes);for(let[R,g]of p.attrs)g===null?c.removeAttribute(R):c.setAttribute(R,g)}l.clear()},a=[],d=0,m=(c,p,R)=>a.push({path:(p??"").trim().slice(0,120),reason:R,on:U(c)});function w(c,p,R){if(p.bind!==void 0){let g=V(R,p.bind);if(g.status!=="value")m(c,p.bind,g.status);else if(!W(c))m(c,p.bind,"refused-element");else{let b=c.localName==="img";if(b?(f(c,"src"),f(c,"srcset"),f(c,"hidden")):i(c),B(g.value))b?K(c,!1):c.textContent="",m(c,p.bind,"empty");else{let h;if(b)h=rt(c,g.value,s,p.width);else if(p.format==="markdown")h=tt(c,g.value,s);else if(p.format==="text")h=Re(c,g.value);else{let k=at(g.value,p.format,c.closest("[lang]")?.getAttribute("lang")??void 0);h=k===null?"type":Re(c,k)}h?m(c,p.bind,h):d++}}}for(let[g,b]of p.attrs){let h=V(R,b);if(h.status!=="value"){m(c,b,h.status);continue}if(f(c,g),B(h.value)){g==="alt"?c.setAttribute("alt",""):c.removeAttribute(g),m(c,b,"empty");continue}let k=c.getAttribute(g),A=st(c,g,h.value,s,p.width);A?(k===null&&c.removeAttribute(g),m(c,b,A)):d++}for(let[g,b]of[[p.show,!0],[p.hide,!1]]){if(g===void 0)continue;let h=V(R,g);if(h.status!=="value"){m(c,g,h.status);continue}f(c,"hidden");let k=!B(h.value)&&h.value!==!1;K(c,k===b),d++}if(p.link!==void 0){let g=[],b=He(p.link,s.base,h=>{let k=V(R,h.join("."));if(k.status==="value")return k.value;g.push(k.status)});if(g[0])m(c,p.link,g[0]);else if(!b.ok)m(c,b.path,b.reason);else{f(c,"href");let h=ot(c,b.url);h?m(c,p.link,h):d++}}}function v(c,p,R){let g=lt(c);if(!g){m(c,"template","unsupported");return}i(c);let b=[g];for(let k of Array.from(c.children))k.hasAttribute(`${S}empty`)&&(f(k,"hidden"),K(k,p.length===0),b.push(k));let h=[];for(let k of p){let A=g.content.cloneNode(!0);x(ie(A,!1),{kind:"record",source:k},R+1),h.push(...Array.from(A.childNodes))}c.replaceChildren(...b,...h),d++}function x(c,p,R){a.push(...c.issues);for(let{el:g,d:b}of c.bound)w(g,b,p);for(let g of c.eaches){let b=V(p,g.path);if(b.status!=="value"){m(g.el,g.path,b.status);continue}if(R>=Kt){m(g.el,g.path,"unsupported");continue}let h=b.value,k=Array.isArray(h)?h:B(h)?[]:[h];if(k.some(A=>A===null||typeof A!="object"||Array.isArray(A))){m(g.el,g.path,"type");continue}k.length===0&&m(g.el,g.path,"empty"),v(g.el,k.map(A=>({data:A})),R)}}async function O(c){try{let p=await c();return p===null?{status:"missing"}:{status:"ok",value:p}}catch(p){return p instanceof D&&p.status===404&&p.code!=="RELEASE_NOT_FOUND"?{status:"missing"}:{status:"failed"}}}let T=null,M="";async function $(c){let p=T===null;p&&t.setAttribute(`${S}state`,"loading");let R=await r.isPreview().catch(()=>!1),g=y=>{T=y,t.setAttribute(`${S}state`,y.state),t.toggleAttribute(`${S}preview`,y.preview);let E=y.issues.filter(I=>I.reason!=="empty"),C=E.map(I=>`${I.path} (${I.reason}) on ${I.on}`).join("; ");return C!==M&&(M=C,E.length>0&&console.warn(`[mapled] ${E.length===1?"1 place":`${E.length} places`} couldn't be filled: ${C}`)),n.dispatchEvent(new CustomEvent(p?"mapled:ready":"mapled:update",{detail:y})),y},b=null;if(!R)if(c!==void 0)b=c;else try{let y=await r.getRelease();if(y===null)return g({state:"unpublished",release:null,preview:R,bound:0,issues:[]});b=y.release}catch{return T!==null&&T.state==="ready"?T:g({state:"fallback",release:null,preview:R,bound:0,issues:[]})}let h=b===null?{}:{release:b},k=ie(t,!0),A=Ae(t,k.issues);A&&k.bound.unshift({el:t,d:A});let L=new Map,le=new Map,Y=new Map,J=[];for(let[y,E]of ut(k))J.push(O(()=>r.getSingle(y,{...h,...E.size>0?{expand:[...E]}:{}})).then(C=>L.set(y,C)));for(let y of k.lists){let E=lt(y.el),C=E?[...ut(ie(E.content,!1)).keys()]:[];J.push(O(async()=>(await r.getRecords(y.collection,{...y.options,...h,...C.length>0?{fields:C}:{}})).records).then(I=>le.set(y,I)))}for(let y of k.records){if(y.slug===null){Y.set(y,{status:"missing"});continue}let E=y.slug;J.push(O(()=>r.getRecordBySlug(y.collection,E,{...h,...y.expand.length>0?{expand:y.expand}:{}})).then(C=>Y.set(y,C)))}await Promise.all(J);let Ce=[...L.values(),...le.values(),...Y.values()];if(Ce.length>0&&Ce.every(y=>y.status==="failed"))return T!==null&&T.state==="ready"?T:g({state:"fallback",release:b,preview:R,bound:0,issues:[]});o(),a=[],d=0,x(k,{kind:"page",singles:L},0);for(let y of k.lists){let E=le.get(y);E?.status==="ok"?v(y.el,E.value,0):m(y.el,y.collection,E?.status??"failed")}for(let y of k.records){let E=Y.get(y);E?.status==="ok"?x(y.block,{kind:"record",source:E.value},0):m(y.el,y.collection,E?.status??"failed")}return Pe(),g({state:"ready",release:b,preview:R,bound:d,issues:a})}let Ee=new WeakSet,xe=new WeakSet;function Pe(){for(let c of Array.from(t.querySelectorAll(`form[${S}form]`)))Ee.has(c)||(Ee.add(c),c.addEventListener("submit",p=>{p.preventDefault(),ft(c)}))}async function ft(c){if(c.getAttribute(`${S}form-state`)==="sending")return;let p=(c.getAttribute(`${S}form`)??"").trim(),R=c.querySelector(`[${S}form-sent]`),g=c.querySelector(`[${S}form-failed]`),b=Array.from(c.querySelectorAll("button, input[type=submit]")).filter(L=>!L.disabled);c.setAttribute(`${S}form-state`,"sending");for(let L of b)L.disabled=!0;let h=c.querySelector(`input[type=checkbox][${S}consent]`),k=h?.checked?(h.labels?.[0]?.textContent??h.closest("label")?.textContent??"").trim().slice(0,500):"",A=ve.test(p)?await de(p,c,{key:e.key,apiUrl:e.apiUrl,fetch:e.fetch,...k?{consent:k}:{}}):{ok:!1,status:0,code:"BAD_FORM",message:"This form isn't set up yet."};for(let L of b)L.disabled=!1;c.setAttribute(`${S}form-state`,A.ok?"sent":"failed"),A.ok&&c.reset(),R&&K(R,A.ok),g&&(!A.ok&&(xe.has(g)||(g.textContent??"").trim()==="")&&(xe.add(g),g.textContent=A.message),K(g,!A.ok)),n.dispatchEvent(new CustomEvent("mapled:form",{detail:A.ok?{form:p,ok:!0}:{form:p,ok:!1,status:A.status,code:A.code}}))}Pe();let Oe=async c=>{try{return await $(c)}catch(p){return console.error(`[mapled] ${p instanceof Error?p.message:"The page couldn't be filled."}`),T??{state:"fallback",release:null,preview:!1,bound:0,issues:[]}}},G=Oe(),X=c=>G=G.then(()=>Oe(c)),$e=c=>{c.target?.closest?.(`[${S}end-preview]`)&&(c.preventDefault(),ee(),X())};n.addEventListener("click",$e);let Z=null;if(e.live){let c=typeof e.live=="number"?e.live:void 0;G.then(p=>{!p.preview&&Z===null&&(Z=r.watch(R=>{X(R.release)},{interval:c}))})}return{ready:G,get report(){return T},refresh:()=>X(),endPreview:()=>(ee(),X()),stop:()=>{Z?.(),Z=()=>{},n.removeEventListener("click",$e)},client:r}}var ct="0.1.0";var dt={version:ct,mount:Te,page:null};window.Mapled=dt;var _=document.currentScript;if(_ instanceof HTMLScriptElement&&_.hasAttribute("data-mapled-key")){let e=_.getAttribute("data-mapled-live"),t=e===null?NaN:parseInt(e,10),n=()=>{try{dt.page=Te({key:_.getAttribute("data-mapled-key")??"",..._.getAttribute("data-mapled-api")?{apiUrl:_.getAttribute("data-mapled-api")}:{},...e===null?{}:{live:Number.isFinite(t)?t:!0}})}catch(r){console.error(r instanceof Error?r.message:"Mapled couldn't start.")}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",n,{once:!0}):n()}})();
7
+ `:"";continue}let a=dt(l);if(a){oe(e,a.text,P(e,`h${a.level}`,n),r),s++;continue}if(xe(l)){P(e,"hr",n),s++;continue}if(Te(l)){let i=[];for(;s<t.length&&Te(t[s]);)i.push(t[s].replace(/^ {0,3}> ?/,"")),s++;Pe(e,i,P(e,"blockquote",n),r+1);continue}let f=X(l);if(f){s=Ht(e,t,s,f,n,r);continue}let o=[l.trimStart()];for(s++;s<t.length&&!Re(t[s])&&!zt(t[s]);)o.push(t[s].trimStart()),s++;oe(e,o.join(`
8
+ `),P(e,"p",n),r)}}function Ht(e,t,n,r,s,l){let c=P(e,r.ordered?"ol":"ul",s);r.ordered&&r.start!==1&&c.setAttribute("start",String(r.start));let a=[],f=!1;for(;n<t.length;){let o=X(t[n]);if(!o||o.ordered!==r.ordered||o.indent!==r.indent||xe(t[n]))break;let i=o.indent+o.width,d=[o.rest];n++;let p=!1;for(;n<t.length;){let k=t[n];if(Re(k)){p=!0,d.push(""),n++;continue}if(G(k)<i)break;p&&d.some(T=>T!=="")&&!X(k.slice(i))&&(f=!0),p=!1,d.push(k.slice(i)),n++}for(;d.length>0&&d[d.length-1]==="";)d.pop();if(p&&n<t.length){let k=X(t[n]);k&&k.ordered===r.ordered&&k.indent===r.indent&&(f=!0)}a.push({lines:d,el:P(e,"li",c)})}for(let o of a)if(Pe(e,o.lines,o.el,l+1),!f){for(let i of Array.from(o.el.childNodes))if(i.nodeName==="P"){for(;i.firstChild;)o.el.insertBefore(i.firstChild,i);o.el.removeChild(i)}}return n}var Me=e=>e===void 0||e===" "||e===`
9
+ `,ft=e=>e!==void 0&&/[\p{L}\p{N}]/u.test(e);function se(e,t,n,r,s=""){let l=Math.min(e.length,r);for(let c=n;c<l;c++){if(e[c]===t)return c;if(s.includes(e[c]))return-1}return-1}function V(e,t,n){let r=t;for(;e[r]===n;)r++;return r}function pt(e,t){if(e[t]==="\\")return t+2;if(e[t]==="`"){let n=V(e,t,"`"),r=mt(e,n,n-t);return r===-1?n:r+(n-t)}return-1}function mt(e,t,n){let r=e.indexOf("`",t);for(;r!==-1;){let s=V(e,r,"`");if(s-r===n)return r;r=e.indexOf("`",s)}return-1}function Wt(e,t,n){let r=n[0],s=t;for(;s<e.length;){let l=pt(e,s);if(l!==-1){s=l;continue}if(e[s]!==r){s++;continue}let c=V(e,s,r),a=c-s;if((n.length===1?a===1||a>=3:a>=n.length)&&s>t&&!Me(e[s-1])&&(r!=="_"||!ft(e[c])))return c-n.length;s=c}return-1}function Xt(e,t){let n=se(e,";",t+1,t+34,`
10
+ &`);if(n===-1)return null;let r=e.slice(t+1,n);if(r[0]==="#"){let l=r[1]==="x"||r[1]==="X",c=r.slice(l?2:1);if(!(l?/^[0-9a-fA-F]{1,6}$/:/^[0-9]{1,7}$/).test(c))return null;let a=parseInt(c,l?16:10);return{char:a>0&&a<=1114111&&!(a>=55296&&a<=57343)?String.fromCodePoint(a):"\uFFFD",end:n+1}}let s=Object.prototype.hasOwnProperty.call(at,r)?at[r]:void 0;return s===void 0?null:{char:s,end:n+1}}var gt=e=>e.replace(/\\([!-/:-@[-`{-~])/g,"$1");function Gt(e,t){if(e[t]!=="(")return null;let n=Math.min(e.length,t+ut+1024),r=t+1;for(;r<n&&Me(e[r])&&e[r]!==void 0;)r++;let s="";if(e[r]==="<"){let c=se(e,">",r+1,n,`
11
+ <`);if(c===-1)return null;s=e.slice(r+1,c),r=c+1}else{let c=r,a=0;for(;r<n;){let f=e[r];if(f==="\\"&&r+1<n){r+=2;continue}if(f===" "||f===`
12
+ `)break;if(f==="("&&a++,f===")"){if(a===0)break;a--}r++}s=e.slice(c,r)}for(;r<n&&(e[r]===" "||e[r]===`
13
+ `);)r++;let l=e[r];if(l==='"'||l==="'"||l==="("){let c=se(e,l==="("?")":l,r+1,n);if(c===-1)return null;for(r=c+1;r<n&&(e[r]===" "||e[r]===`
14
+ `);)r++}return e[r]!==")"?null:{address:gt(s),end:r+1}}function Ee(e,t,n=!1){let r=t+1;for(;r<e.length;){let l=pt(e,r);if(l!==-1){r=l;continue}if(!n&&e[r]==="!"&&e[r+1]==="["){let c=Ee(e,r+1,!0);if(!c)return null;r=c.end;continue}if(e[r]==="[")return null;if(e[r]==="]")break;r++}if(r>=e.length)return null;let s=Gt(e,r+1);return s?{label:e.slice(t+1,r),address:s.address,end:s.end}:null}var Vt=/^(?:[a-z][a-z0-9+.-]{1,31}:[^\s<>]*|[^\s<>@]+@[^\s<>@]+\.[^\s<>@]+)$/i;function oe(e,t,n,r){if(r>=lt){n.appendChild(e.doc.createTextNode(t));return}let s="",l=()=>{s!==""&&n.appendChild(e.doc.createTextNode(s)),s=""},c=new Set,a=0;for(;a<t.length;){let f=t[a];if(f==="\\"){let o=t[a+1];if(o===`
15
+ `)for(l(),P(e,"br",n),a+=2;t[a]===" ";)a++;else o!==void 0&&qt.includes(o)?(s+=o,a+=2):(s+=f,a++);continue}if(f===`
16
+ `){let o=s.endsWith(" "),i=s.length;for(;i>0&&s[i-1]===" ";)i--;for(s=s.slice(0,i),o?(l(),P(e,"br",n)):s+=`
17
+ `,a++;t[a]===" ";)a++;continue}if(f==="`"){let o=V(t,a,"`"),i=mt(t,o,o-a);if(i===-1){s+=t.slice(a,o),a=o;continue}let d=t.slice(o,i).replace(/\n/g," ");d.length>1&&d.startsWith(" ")&&d.endsWith(" ")&&d.trim()!==""&&(d=d.slice(1,-1)),l(),P(e,"code",n).textContent=d,a=i+(o-a);continue}if(f==="!"&&t[a+1]==="["){let o=Ee(t,a+1);if(o){let i=gt(o.label),d=F(o.address.trim(),e.base,"media");if(d===null)s+=i;else{l();let p=P(e,"img",n);p.setAttribute("src",d),p.setAttribute("alt",i),p.setAttribute("loading","lazy")}a=o.end;continue}}if(f==="["){let o=Ee(t,a);if(o){let i=F(o.address.trim(),e.base,"link");l();let d=i===null?n:P(e,"a",n);i!==null&&d.setAttribute("href",i),oe(e,o.label,d,r+1),a=o.end;continue}}if(f==="<"){let o=se(t,">",a+1,a+ut,`
18
+ <`),i=o===-1?null:t.slice(a+1,o);if(i!==null&&Vt.test(i)){let d=F(i.includes(":")?i:`mailto:${i}`,e.base,"link");if(d!==null){l();let p=P(e,"a",n);p.setAttribute("href",d),p.textContent=i,a=o+1;continue}}}if(f==="&"){let o=Xt(t,a);if(o){s+=o.char,a=o.end;continue}}if(f==="*"||f==="_"||f==="~"){let o=V(t,a,f),i=o-a,d=!Me(t[o])&&(f!=="_"||!ft(t[a-1])),p=f==="~"?i>=2?[["~~",["del"]]]:[]:[...i>=3?[[f.repeat(3),["em","strong"]]]:[],...i>=2?[[f.repeat(2),["strong"]]]:[],[f,["em"]]],k=!1;if(d)for(let[T,x]of p){if(c.has(T))continue;let M=a+T.length,S=Wt(t,M,T);if(S===-1){c.add(T);continue}if(S===M)continue;l();let C=n;for(let O of x)C=P(e,O,C);oe(e,t.slice(M,S),C,r+1),a=S+T.length,k=!0;break}k||(s+=t.slice(a,o),a=o);continue}s+=f,a++}l()}var Zt="http://www.w3.org/1999/xhtml",Yt=new Set(["script","style","iframe","frame","frameset","object","embed","applet","base","link","meta","template","noscript"]),ie={href:{on:["a","area"],holds:"link"},src:{on:["img","video","audio","source"],holds:"media"},alt:{on:["img","area"],holds:"text"},title:{on:null,holds:"text"},"aria-label":{on:null,holds:"text"},placeholder:{on:["input","textarea"],holds:"text"},datetime:{on:["time","del","ins"],holds:"text"}},ae=e=>e.namespaceURI===Zt,Z=e=>!Yt.has(e.localName.toLowerCase());function Oe(e,t){if(!Z(e))return"refused-element";let n=Ae(t);return n===null?"type":(e.textContent=n,null)}function ht(e,t,n){return!Z(e)||!ae(e)?"refused-element":typeof t!="string"?"type":(e.replaceChildren(ct(t,e.ownerDocument,n.base)),null)}function yt(e,t,n){return typeof e!="string"?null:ot(e)?rt(e,{...t.apiUrl?{apiUrl:t.apiUrl}:{},...n?{width:n}:{}}):F(e,t.base,"media")}function bt(e,t,n,r){if(!ae(e)||e.localName!=="img")return"refused-element";if(typeof t!="string")return"type";let s=yt(t,n,r);return s===null?"unsafe-url":(e.removeAttribute("srcset"),e.setAttribute("src",s),null)}function wt(e,t,n,r,s){let l=t.toLowerCase(),c=Object.prototype.hasOwnProperty.call(ie,l)?ie[l]:void 0;if(!c)return"unsupported";if(!Z(e)||!ae(e))return"refused-element";if(c.on!==null&&!c.on.includes(e.localName))return"unsupported";if(c.holds==="text"){let f=Ae(n);return f===null?"type":(e.setAttribute(l,f),null)}if(typeof n!="string")return"type";let a=c.holds==="media"?yt(n,r,e.localName==="img"?s:void 0):F(n,r.base,"link");return a===null?"unsafe-url":(e.setAttribute(l,a),null)}function kt(e,t){return!ae(e)||e.localName!=="a"&&e.localName!=="area"?"unsupported":(e.setAttribute("href",t),null)}function K(e,t){t?e.removeAttribute("hidden"):e.setAttribute("hidden","")}var St=["text","markdown","date","datetime","number"],Jt=/^\d{4}-\d{2}-\d{2}$/,Qt=/^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;function At(e,t,n){let r=n&&/^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$/.test(n)?n:void 0;try{if(t==="number"){let c=typeof e=="number"?e:typeof e=="string"&&e.trim()!==""?Number(e):NaN;return Number.isFinite(c)?new Intl.NumberFormat(r).format(c):null}if(typeof e!="string"||!Qt.test(e))return null;let s=new Date(e);if(Number.isNaN(s.getTime()))return null;let l=Jt.test(e);return new Intl.DateTimeFormat(r,{dateStyle:"long",...t==="datetime"&&!l?{timeStyle:"short"}:{},...l?{timeZone:"UTC"}:{}}).format(s)}catch{return null}}var w="data-mapled-",en=new Set(["bind","format","width","show","hide","link","list","each","record","slug","slug-param","sort","limit","filter","expand","empty","form","form-state","form-sent","form-failed","consent","end-preview","state","preview","key","api","live"]),Ce=/^[a-z0-9][a-z0-9_-]{0,63}$/,tn=/^mk_[A-Za-z0-9_]{8,128}$/,nn=4,rn=100,sn=2;function J(e,t=0){if(e===null||typeof e!="object"||Array.isArray(e))return!1;let{data:n,expanded:r}=e;if(n===null||typeof n!="object"||Array.isArray(n))return!1;if(r===void 0)return!0;if(r===null||typeof r!="object"||Array.isArray(r))return!1;let s=Object.values(r);return t>=sn?s.length===0:s.every(l=>l===null||(Array.isArray(l)?l.every(c=>J(c,t+1)):J(l,t+1)))}var on=e=>Array.isArray(e)&&e.every(t=>J(t));function N(e){let t=e.getAttribute("id");return`${e.localName}${t&&/^[\w-]{1,40}$/.test(t)?`#${t}`:""}`}var ue=e=>(e??"").split(",").map(t=>t.trim()).filter(t=>/^[a-z0-9][a-z0-9_.-]{0,127}$/.test(t)),Rt=e=>Array.from(e.children).find(t=>t.localName==="template")??null;function $e(e,t){let n=null,r=()=>n??(n={format:"text",attrs:[],expand:[]});for(let a of Array.from(e.attributes)){if(!a.name.startsWith(w))continue;let f=a.name.slice(w.length);if(f==="bind")r().bind=a.value;else if(f.startsWith("bind-")){let o=f.slice(5);Object.prototype.hasOwnProperty.call(ie,o)?r().attrs.push([o,a.value]):t.push({path:a.value.slice(0,80),reason:"unsupported",on:`${N(e)}[${a.name.slice(0,60)}]`})}else f==="show"?r().show=a.value:f==="hide"?r().hide=a.value:f==="link"?r().link=a.value:en.has(f)||t.push({path:a.value.slice(0,80),reason:"unsupported",on:`${N(e)}[${a.name.slice(0,60)}]`})}if(!n)return null;let s=n,l=e.getAttribute(`${w}format`);l!==null&&(St.includes(l)?s.format=l:t.push({path:l.slice(0,80),reason:"bad-path",on:`${N(e)}[${w}format]`}));let c=parseInt(e.getAttribute(`${w}width`)??"",10);return c>=16&&c<=4096&&(s.width=c),s.expand=ue(e.getAttribute(`${w}expand`)),s}function an(e,t){let n={},r=e.getAttribute(`${w}sort`);r!==null&&(/^-?[a-z0-9][a-z0-9_-]{0,63}$/.test(r.trim())?n.sort=r.trim():t.push({path:r.slice(0,80),reason:"bad-path",on:`${N(e)}[${w}sort]`}));let s=parseInt(e.getAttribute(`${w}limit`)??"",10);s>=1&&s<=100&&(n.limit=s);let l=e.getAttribute(`${w}filter`);if(l!==null)for(let a of l.split(";")){if(a.trim()==="")continue;let f=a.indexOf("="),o=f===-1?"":a.slice(0,f).trim(),i=f===-1?"":a.slice(f+1).trim();Ce.test(o)&&i!==""&&i.length<=200?(n.filter??(n.filter={}))[o]=i:t.push({path:a.trim().slice(0,80),reason:"bad-path",on:`${N(e)}[${w}filter]`})}let c=ue(e.getAttribute(`${w}expand`));return c.length>0&&(n.expand=c),n}function le(e,t){let n={bound:[],eaches:[],lists:[],records:[],issues:[]},r=s=>{if(s.hasAttributes()){let l=s.getAttribute(`${w}list`),c=s.getAttribute(`${w}record`),a=s.getAttribute(`${w}each`);if(l!==null||c!==null){let o=(l??c??"").trim();if(!t)n.issues.push({path:o.slice(0,80),reason:"unsupported",on:N(s)});else if(!Ce.test(o))n.issues.push({path:o.slice(0,80),reason:"bad-path",on:N(s)});else if(l!==null)n.lists.push({el:s,collection:o,options:an(s,n.issues)});else{let i=s.getAttribute(`${w}slug-param`),d=s.getAttribute(`${w}slug`)??(i===null?null:new URLSearchParams(s.ownerDocument.location?.search??"").get(i)),p=le(s,!0);for(let T of p.records)n.issues.push({path:T.collection,reason:"unsupported",on:N(T.el)});n.lists.push(...p.lists),n.issues.push(...p.issues);let k=$e(s,n.issues);k&&p.bound.unshift({el:s,d:k}),n.records.push({el:s,collection:o,slug:d!==null&&d.trim()!==""&&d.length<=200?d.trim():null,expand:ue(s.getAttribute(`${w}expand`)),block:{...p,lists:[],records:[],issues:[]}})}return}if(a!==null){n.eaches.push({el:s,path:a});return}let f=$e(s,n.issues);f&&n.bound.push({el:s,d:f})}for(let l of Array.from(s.children))r(l)};for(let s of Array.from(e.children))r(s);return n}function vt(e){let t=new Map,n=(r,s=[])=>{let l=H(r)?.[0];if(!l)return;let c=t.get(l)??new Set;for(let a of s)c.add(a);t.set(l,c)};for(let{d:r}of e.bound){n(r.bind,r.expand);for(let[,s]of r.attrs)n(s,r.expand);n(r.show,r.expand),n(r.hide,r.expand);for(let s of(r.link??"").matchAll(/\{([^{}]*)\}/g))n(s[1],r.expand)}for(let r of e.eaches)n(r.path,ue(r.el.getAttribute(`${w}expand`)));return t}function Y(e,t){let n=H(t);if(!n)return{status:"bad-path"};if(e.kind==="record")return{status:"value",value:Se(e.source,n)};if(n.length<2)return{status:"bad-path"};let r=e.singles.get(n[0]);return!r||r.status!=="ok"?{status:r?.status==="failed"?"failed":"missing"}:{status:"value",value:Se(r.value,n.slice(1))}}function Le(e){if(typeof e?.key!="string"||!tn.test(e.key))throw new Error("Mapled: data-mapled-key takes the delivery key (mk_\u2026) \u2014 the one key that is safe in a page. A server key or a secret never goes into HTML.");if(typeof document>"u")throw new Error("Mapled: @mapled/vanilla fills a page \u2014 it runs in a browser. On a server read with @mapled/client.");let t=e.root??document.documentElement,n=t.ownerDocument,r=st({key:e.key,apiUrl:e.apiUrl,appUrl:e.appUrl,fetch:e.fetch}),s={apiUrl:e.apiUrl,base:n.baseURI},l=new Map,c=u=>{let m=l.get(u);return m||l.set(u,m={attrs:new Map}),m},a=u=>{let m=c(u);m.nodes??(m.nodes=Array.from(u.childNodes))},f=(u,m)=>{let A=c(u);A.attrs.has(m)||A.attrs.set(m,u.getAttribute(m))},o=()=>{for(let[u,m]of l){m.nodes&&u.replaceChildren(...m.nodes);for(let[A,g]of m.attrs)g===null?u.removeAttribute(A):u.setAttribute(A,g)}l.clear()},i=[],d=0,p=(u,m,A)=>i.push({path:(m??"").trim().slice(0,120),reason:A,on:N(u)});function k(u,m,A){if(m.bind!==void 0){let g=Y(A,m.bind);if(g.status!=="value")p(u,m.bind,g.status);else if(!Z(u))p(u,m.bind,"refused-element");else{let y=u.localName==="img";if(y?(f(u,"src"),f(u,"srcset"),f(u,"hidden")):a(u),W(g.value))y?K(u,!1):u.textContent="",p(u,m.bind,"empty");else{let b;if(y)b=bt(u,g.value,s,m.width);else if(m.format==="markdown")b=ht(u,g.value,s);else if(m.format==="text")b=Oe(u,g.value);else{let R=At(g.value,m.format,u.closest("[lang]")?.getAttribute("lang")??void 0);b=R===null?"type":Oe(u,R)}b?p(u,m.bind,b):d++}}}for(let[g,y]of m.attrs){let b=Y(A,y);if(b.status!=="value"){p(u,y,b.status);continue}if(f(u,g),W(b.value)){g==="alt"?u.setAttribute("alt",""):u.removeAttribute(g),p(u,y,"empty");continue}let R=u.getAttribute(g),v=wt(u,g,b.value,s,m.width);v?(R===null&&u.removeAttribute(g),p(u,y,v)):d++}for(let[g,y]of[[m.show,!0],[m.hide,!1]]){if(g===void 0)continue;let b=Y(A,g);if(b.status!=="value"){p(u,g,b.status);continue}f(u,"hidden");let R=!W(b.value)&&b.value!==!1;K(u,R===y),d++}if(m.link!==void 0){let g=[],y=it(m.link,s.base,b=>{let R=Y(A,b.join("."));if(R.status==="value")return R.value;g.push(R.status)});if(g[0])p(u,m.link,g[0]);else if(!y.ok)p(u,y.path,y.reason);else{f(u,"href");let b=kt(u,y.url);b?p(u,m.link,b):d++}}}function T(u,m,A){let g=Rt(u);if(!g){p(u,"template","unsupported");return}a(u);let y=[g];for(let R of Array.from(u.children))R.hasAttribute(`${w}empty`)&&(f(R,"hidden"),K(R,m.length===0),y.push(R));let b=[];for(let R of m.slice(0,rn)){let v=g.content.cloneNode(!0);x(le(v,!1),{kind:"record",source:R},A+1),b.push(...Array.from(v.childNodes))}u.replaceChildren(...y,...b),d++}function x(u,m,A){i.push(...u.issues);for(let{el:g,d:y}of u.bound)k(g,y,m);for(let g of u.eaches){let y=Y(m,g.path);if(y.status!=="value"){p(g.el,g.path,y.status);continue}if(A>=nn){p(g.el,g.path,"unsupported");continue}let b=y.value,R=Array.isArray(b)?b:W(b)?[]:[b];if(R.some(v=>v===null||typeof v!="object"||Array.isArray(v))){p(g.el,g.path,"type");continue}R.length===0&&p(g.el,g.path,"empty"),T(g.el,R.map(v=>({data:v})),A)}}async function M(u,m){try{let A=await u();return A===null?{status:"missing"}:m(A)?{status:"ok",value:A}:{status:"failed",answered:!0}}catch(A){return A instanceof j&&A.status===404&&A.code!=="RELEASE_NOT_FOUND"?{status:"missing"}:{status:"failed"}}}let S=null,C="",O=null,q,Ue=!1,Q=0,Ne=-1,xt=3,Pt=typeof e.live=="number"?e.live:void 0;function Ie(){o(),S={state:"fallback",release:null,preview:!1,bound:0,issues:[]},t.setAttribute(`${w}state`,"fallback"),t.removeAttribute(`${w}preview`)}function De(){Q++,clearTimeout(q),S?.preview&&Ie()}function Mt(){clearTimeout(q);let u=_();if(!u||Ue)return;let m=Date.parse(u.expiresAt)-Date.now();q=setTimeout(()=>{_()===null&&De(),de()},Math.min(Math.max(m,0)+1,2147483647))}async function Fe(u,m=1){let A=S===null;A&&t.setAttribute(`${w}state`,"loading");let g=Q,y=await r.isPreview().catch(()=>!1),b=y?_()?.draftToken??null:null;if(S!==null&&S.preview&&!y&&Ie(),!y&&u!==void 0&&S!==null&&S.state==="ready"&&!S.preview&&S.release!==null&&u<=S.release)return S;let R=h=>{S=h,Ne=g,t.setAttribute(`${w}state`,h.state),t.toggleAttribute(`${w}preview`,h.preview);let E=h.issues.filter(U=>U.reason!=="empty"),$=E.map(U=>`${U.path} (${U.reason}) on ${U.on}`).join("; ");return $!==C&&(C=$,E.length>0&&console.warn(`[mapled] ${E.length===1?"1 place":`${E.length} places`} couldn't be filled: ${$}`)),n.dispatchEvent(new CustomEvent(A?"mapled:ready":"mapled:update",{detail:h})),h.preview?Mt():(clearTimeout(q),e.live&&O===null&&(O=r.watch(U=>{de(U.release)},{interval:Pt}))),h},v=null;if(!y)if(u!==void 0)v=u;else try{let h=await r.getRelease();if(h===null)return o(),R({state:"unpublished",release:null,preview:y,bound:0,issues:[]});v=h.release}catch{return S!==null&&S.state==="ready"?S:R({state:"fallback",release:null,preview:y,bound:0,issues:[]})}let L=v===null?{}:{release:v},I=le(t,!0),ze=$e(t,I.issues);ze&&I.bound.unshift({el:t,d:ze});let fe=new Map,pe=new Map,ee=new Map,te=[];for(let[h,E]of vt(I))te.push(M(()=>r.getSingle(h,{...L,...E.size>0?{expand:[...E]}:{}}),J).then($=>fe.set(h,$)));for(let h of I.lists){let E=Rt(h.el),$=E?[...vt(le(E.content,!1)).keys()]:[];te.push(M(async()=>(await r.getRecords(h.collection,{...h.options,...L,...$.length>0?{fields:$}:{}})).records,on).then(U=>pe.set(h,U)))}for(let h of I.records){if(h.slug===null){ee.set(h,{status:"missing"});continue}let E=h.slug;te.push(M(()=>r.getRecordBySlug(h.collection,E,{...L,...h.expand.length>0?{expand:h.expand}:{}}),J).then($=>ee.set(h,$)))}await Promise.all(te);let He=await r.isPreview().catch(()=>!1)?_()?.draftToken??null:null;if(g!==Q||He!==b)return m<xt?Fe(u,m+1):(o(),R({state:"fallback",release:null,preview:He!==null,bound:0,issues:[]}));let We=[...fe.values(),...pe.values(),...ee.values()];if(We.length>0&&We.every(h=>h.status==="failed"&&!h.answered))return S!==null&&S.state==="ready"?S:R({state:"fallback",release:v,preview:y,bound:0,issues:[]});o(),i=[],d=0,x(I,{kind:"page",singles:fe},0);for(let h of I.lists){let E=pe.get(h);E?.status==="ok"?T(h.el,E.value,0):p(h.el,h.collection,E?.status??"failed")}for(let h of I.records){let E=ee.get(h);E?.status==="ok"?x(h.block,{kind:"record",source:E.value},0):p(h.el,h.collection,E?.status??"failed")}return Ke(),R({state:"ready",release:v,preview:y,bound:d,issues:i})}let _e=new WeakSet,je=new WeakSet;function Ke(){for(let u of Array.from(t.querySelectorAll(`form[${w}form]`)))_e.has(u)||(_e.add(u),u.addEventListener("submit",m=>{m.preventDefault(),Ot(u)}))}async function Ot(u){if(u.getAttribute(`${w}form-state`)==="sending")return;let m=(u.getAttribute(`${w}form`)??"").trim(),A=u.querySelector(`[${w}form-sent]`),g=u.querySelector(`[${w}form-failed]`),y=Array.from(u.querySelectorAll("button, input[type=submit]")).filter(L=>!L.disabled);u.setAttribute(`${w}form-state`,"sending");for(let L of y)L.disabled=!0;let b=u.querySelector(`input[type=checkbox][${w}consent]`),R=b?.checked?(b.labels?.[0]?.textContent??b.closest("label")?.textContent??"").trim().slice(0,500):"",v=Ce.test(m)?await we(m,u,{key:e.key,apiUrl:e.apiUrl,fetch:e.fetch,...R?{consent:R}:{}}):{ok:!1,status:0,code:"BAD_FORM",message:"This form isn't set up yet."};for(let L of y)L.disabled=!1;u.setAttribute(`${w}form-state`,v.ok?"sent":"failed"),v.ok&&u.reset(),A&&K(A,v.ok),g&&(!v.ok&&(je.has(g)||(g.textContent??"").trim()==="")&&(je.add(g),g.textContent=v.message),K(g,!v.ok)),n.dispatchEvent(new CustomEvent("mapled:form",{detail:v.ok?{form:m,ok:!0}:{form:m,ok:!1,status:v.status,code:v.code}}))}Ke();let ce=async u=>{try{return await Fe(u)}catch(m){return console.error(`[mapled] ${m instanceof Error?m.message:"The page couldn't be filled."}`),S??{state:"fallback",release:null,preview:!1,bound:0,issues:[]}}},z=ce(),de=u=>z=z.then(()=>ce(u)),Be=()=>{ye(),De();let u=Q;return z=z.then(()=>Ne>=u&&S!==null?S:ce())},qe=u=>{u.target?.closest?.(`[${w}end-preview]`)&&(u.preventDefault(),Be())};return n.addEventListener("click",qe),{ready:z,get report(){return S},refresh:()=>de(),endPreview:Be,stop:()=>{Ue=!0,O?.(),O=()=>{},clearTimeout(q),n.removeEventListener("click",qe)},client:r}}var Tt="0.1.1";var Et={version:Tt,mount:Le,page:null};window.Mapled=Et;var B=document.currentScript;if(B instanceof HTMLScriptElement&&B.hasAttribute("data-mapled-key")){let e=B.getAttribute("data-mapled-live"),t=e===null?NaN:parseInt(e,10),n=()=>{try{Et.page=Le({key:B.getAttribute("data-mapled-key")??"",...B.getAttribute("data-mapled-api")?{apiUrl:B.getAttribute("data-mapled-api")}:{},...e===null?{}:{live:Number.isFinite(t)?t:!0}})}catch(r){console.error(r instanceof Error?r.message:"Mapled couldn't start.")}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",n,{once:!0}):n()}})();
@@ -1 +1 @@
1
- sha384-mbuMcQAueviAbkTzgvxc8oDtspuYH6lFLUgE+gocGexnI8ehgSgdjnNMNL7JPk4q
1
+ sha384-2vgQ4g9re/eiYxEa/H3WKpWI5C9L4wCB/62c8Kq+LOfZDzmqc2ozqMGC8mZoOUqk
package/dist/markdown.js CHANGED
@@ -445,7 +445,12 @@ function inline(ctx, text, parent, depth) {
445
445
  }
446
446
  if (ch === "\n") {
447
447
  const hard = buffer.endsWith(" ");
448
- buffer = buffer.replace(/ +$/, "");
448
+ // trailing spaces go — read from the end: a pattern anchored there would try every
449
+ // space of a long run inside the line, once per soft break (quadratic, found by review)
450
+ let end = buffer.length;
451
+ while (end > 0 && buffer[end - 1] === " ")
452
+ end--;
453
+ buffer = buffer.slice(0, end);
449
454
  if (hard) {
450
455
  flush();
451
456
  make(ctx, "br", parent);
package/dist/runtime.d.ts CHANGED
@@ -44,7 +44,8 @@ export type Issue = {
44
44
  };
45
45
  export type Report = {
46
46
  /** ready — filled from Mapled; unpublished — nothing is published yet;
47
- fallback — Mapled couldn't be reached, the page is as written */
47
+ fallback — the page is as written: Mapled couldn't be reached, or
48
+ preview just ended and what is published is on its way */
48
49
  state: "ready" | "unpublished" | "fallback";
49
50
  release: number | null;
50
51
  preview: boolean;
package/dist/runtime.js CHANGED
@@ -27,7 +27,7 @@
27
27
 
28
28
  Paths start at a single from the document (`home.headline`) and at the
29
29
  record inside a list, an each or a record (`title`, `author.name`). */
30
- import { createClient, endPreview, MapledError, submitForm } from "@mapled/client";
30
+ import { createClient, endPreview, MapledError, previewSession, submitForm } from "@mapled/client";
31
31
  import { isEmpty, parsePath, valueAt } from "./paths.js";
32
32
  import { ATTRIBUTES, FORMATS, formatted, setVisible, writable, writeAttribute, writeImage, writeLink, writeMarkdown, writeText } from "./sinks.js";
33
33
  import { fillTemplate } from "./url.js";
@@ -46,6 +46,31 @@ export const NAMES = new Set([
46
46
  const KEY = /^[a-z0-9][a-z0-9_-]{0,63}$/;
47
47
  const DELIVERY_KEY = /^mk_[A-Za-z0-9_]{8,128}$/;
48
48
  const MAX_EACH_DEPTH = 4;
49
+ /** The most a template repeats: the API's page, and the most items a
50
+ repeatable group holds — an answer that brings more is cut here. */
51
+ const MAX_ITEMS = 100;
52
+ /** How deep `expand` reaches: `author`, `related.author`. */
53
+ const MAX_EXPAND_DEPTH = 2;
54
+ /** A record as Mapled serves one — what every path walks: `data` an
55
+ object; `expanded`, when there, one linked record, a list of them or
56
+ null under each key, no deeper than `expand` can ask. An answer is
57
+ data, and so is its shape: what isn't a record is read as no answer. */
58
+ function isRecord(value, depth = 0) {
59
+ if (value === null || typeof value !== "object" || Array.isArray(value))
60
+ return false;
61
+ const { data, expanded } = value;
62
+ if (data === null || typeof data !== "object" || Array.isArray(data))
63
+ return false;
64
+ if (expanded === undefined)
65
+ return true;
66
+ if (expanded === null || typeof expanded !== "object" || Array.isArray(expanded))
67
+ return false;
68
+ const linked = Object.values(expanded);
69
+ if (depth >= MAX_EXPAND_DEPTH)
70
+ return linked.length === 0;
71
+ return linked.every((one) => one === null || (Array.isArray(one) ? one.every((r) => isRecord(r, depth + 1)) : isRecord(one, depth + 1)));
72
+ }
73
+ const isRecordList = (value) => Array.isArray(value) && value.every((r) => isRecord(r));
49
74
  /** The element as the page names it: `a#cta`. The id is the author's. */
50
75
  function nameOf(el) {
51
76
  const id = el.getAttribute("id");
@@ -392,7 +417,7 @@ export function mount(options) {
392
417
  kept.push(child);
393
418
  }
394
419
  const items = [];
395
- for (const source of sources) {
420
+ for (const source of sources.slice(0, MAX_ITEMS)) {
396
421
  const clone = template.content.cloneNode(true);
397
422
  fill(compile(clone, false), { kind: "record", source }, depth + 1);
398
423
  items.push(...Array.from(clone.childNodes));
@@ -426,10 +451,13 @@ export function mount(options) {
426
451
  repeat(each.el, items.map((item) => ({ data: item })), depth);
427
452
  }
428
453
  }
429
- async function read(load) {
454
+ async function read(load, wellFormed) {
430
455
  try {
431
456
  const value = await load();
432
- return value === null ? { status: "missing" } : { status: "ok", value };
457
+ if (value === null)
458
+ return { status: "missing" };
459
+ // an answer of another shape than Mapled's is no answer: the place keeps the author's HTML
460
+ return wellFormed(value) ? { status: "ok", value } : { status: "failed", answered: true };
433
461
  }
434
462
  catch (err) {
435
463
  // an unknown collection or single is the page's mistake, not an outage
@@ -438,13 +466,64 @@ export function mount(options) {
438
466
  }
439
467
  let last = null;
440
468
  let warned = "";
441
- async function run(known) {
469
+ let stopWatching = null;
470
+ let expiry;
471
+ let stopped = false;
472
+ /** moves when preview is left: a fill that began before it commits nothing */
473
+ let generation = 0;
474
+ /** the generation of the last fill that committed: an exit's own fill is skipped when one already has */
475
+ let committed = -1;
476
+ /** how many times a fill starts over when the session changed under it */
477
+ const MAX_ATTEMPTS = 3;
478
+ const interval = typeof options.live === "number" ? options.live : undefined;
479
+ /** Preview is over — the page's own way out, or the session's end: the
480
+ page is as written again, and says so, before anything is asked of
481
+ Mapled; what is published follows when it is in hand. */
482
+ function leave() {
483
+ restore();
484
+ last = { state: "fallback", release: null, preview: false, bound: 0, issues: [] };
485
+ root.setAttribute(`${P}state`, "fallback");
486
+ root.removeAttribute(`${P}preview`);
487
+ }
488
+ /** Preview ends now, not after the fill in flight: the draft goes at
489
+ once, and whatever that fill brings back is dropped. */
490
+ function drop() {
491
+ generation++;
492
+ clearTimeout(expiry);
493
+ if (last?.preview)
494
+ leave();
495
+ }
496
+ /** The session's end is a fill of its own: no draft is shown past it —
497
+ the timer stays set through fills that fail or stall. */
498
+ function watchExpiry() {
499
+ clearTimeout(expiry);
500
+ const session = previewSession();
501
+ if (!session || stopped)
502
+ return;
503
+ const left = Date.parse(session.expiresAt) - Date.now();
504
+ expiry = setTimeout(() => {
505
+ if (previewSession() === null)
506
+ drop();
507
+ void refresh();
508
+ }, Math.min(Math.max(left, 0) + 1, 0x7fffffff));
509
+ }
510
+ async function run(known, attempt = 1) {
442
511
  const first = last === null;
443
512
  if (first)
444
513
  root.setAttribute(`${P}state`, "loading");
514
+ const mine = generation;
445
515
  const preview = await client.isPreview().catch(() => false);
516
+ // the session the drafts are read with: an answer read with another one is not this fill's
517
+ const session = preview ? (previewSession()?.draftToken ?? null) : null;
518
+ // a tab that left preview, or whose session ended, shows nothing of the drafts — before anything is asked
519
+ if (last !== null && last.preview && !preview)
520
+ leave();
521
+ // releases only grow (a rollback is a new one): a fill pinned to one the page already shows filled, or an older one, has nothing to add — a page left as written keeps trying
522
+ if (!preview && known !== undefined && last !== null && last.state === "ready" && !last.preview && last.release !== null && known <= last.release)
523
+ return last;
446
524
  const finish = (report) => {
447
525
  last = report;
526
+ committed = mine;
448
527
  root.setAttribute(`${P}state`, report.state);
449
528
  root.toggleAttribute(`${P}preview`, report.preview);
450
529
  const loud = report.issues.filter((i) => i.reason !== "empty");
@@ -455,6 +534,14 @@ export function mount(options) {
455
534
  console.warn(`[mapled] ${loud.length === 1 ? "1 place" : `${loud.length} places`} couldn't be filled: ${text}`);
456
535
  }
457
536
  doc.dispatchEvent(new CustomEvent(first ? "mapled:ready" : "mapled:update", { detail: report }));
537
+ if (report.preview)
538
+ watchExpiry();
539
+ else {
540
+ clearTimeout(expiry);
541
+ // drafts don't move with releases: a tab watches once it shows what is published
542
+ if (options.live && stopWatching === null)
543
+ stopWatching = client.watch((next) => void refresh(next.release), { interval });
544
+ }
458
545
  return report;
459
546
  };
460
547
  // drafts have no release; what is published is read pinned to one, so a
@@ -467,12 +554,15 @@ export function mount(options) {
467
554
  else {
468
555
  try {
469
556
  const pointer = await client.getRelease();
470
- if (pointer === null)
557
+ if (pointer === null) {
558
+ // nothing is published: the page is as written — a draft it showed goes too
559
+ restore();
471
560
  return finish({ state: "unpublished", release: null, preview, bound: 0, issues: [] });
561
+ }
472
562
  release = pointer.release;
473
563
  }
474
564
  catch {
475
- // out of reach: the page stays as it is — as written, or as last filled
565
+ // out of reach: the page stays as it is — as written, or as last filled from what is published
476
566
  return last !== null && last.state === "ready" ? last : finish({ state: "fallback", release: null, preview, bound: 0, issues: [] });
477
567
  }
478
568
  }
@@ -488,12 +578,12 @@ export function mount(options) {
488
578
  const records = new Map();
489
579
  const reads = [];
490
580
  for (const [key, expand] of heads(page)) {
491
- reads.push(read(() => client.getSingle(key, { ...pin, ...(expand.size > 0 ? { expand: [...expand] } : {}) })).then((r) => singles.set(key, r)));
581
+ reads.push(read(() => client.getSingle(key, { ...pin, ...(expand.size > 0 ? { expand: [...expand] } : {}) }), isRecord).then((r) => singles.set(key, r)));
492
582
  }
493
583
  for (const list of page.lists) {
494
584
  const template = templateOf(list.el);
495
585
  const fields = template ? [...heads(compile(template.content, false)).keys()] : [];
496
- reads.push(read(async () => (await client.getRecords(list.collection, { ...list.options, ...pin, ...(fields.length > 0 ? { fields } : {}) })).records).then((r) => lists.set(list, r)));
586
+ reads.push(read(async () => (await client.getRecords(list.collection, { ...list.options, ...pin, ...(fields.length > 0 ? { fields } : {}) })).records, isRecordList).then((r) => lists.set(list, r)));
497
587
  }
498
588
  for (const record of page.records) {
499
589
  if (record.slug === null) {
@@ -501,11 +591,22 @@ export function mount(options) {
501
591
  continue;
502
592
  }
503
593
  const slug = record.slug;
504
- reads.push(read(() => client.getRecordBySlug(record.collection, slug, { ...pin, ...(record.expand.length > 0 ? { expand: record.expand } : {}) })).then((r) => records.set(record, r)));
594
+ reads.push(read(() => client.getRecordBySlug(record.collection, slug, { ...pin, ...(record.expand.length > 0 ? { expand: record.expand } : {}) }), isRecord).then((r) => records.set(record, r)));
505
595
  }
506
596
  await Promise.all(reads);
597
+ // preview was left, or the session ended or was replaced, while the reads were on their way:
598
+ // what they brought is nobody's now — read again, with whatever the tab has
599
+ const now = (await client.isPreview().catch(() => false)) ? (previewSession()?.draftToken ?? null) : null;
600
+ if (mine !== generation || now !== session) {
601
+ if (attempt < MAX_ATTEMPTS)
602
+ return run(known, attempt + 1);
603
+ // the session keeps changing under the reads: show nothing of any of them — the page as written, until the next fill
604
+ restore();
605
+ return finish({ state: "fallback", release: null, preview: now !== null, bound: 0, issues: [] });
606
+ }
607
+ // nothing came back at all: an outage, and the page stays as it is — a wrong-shaped answer is still an answer, reported by its place
507
608
  const answers = [...singles.values(), ...lists.values(), ...records.values()];
508
- if (answers.length > 0 && answers.every((a) => a.status === "failed")) {
609
+ if (answers.length > 0 && answers.every((a) => a.status === "failed" && !a.answered)) {
509
610
  return last !== null && last.state === "ready" ? last : finish({ state: "fallback", release, preview, bound: 0, issues: [] });
510
611
  }
511
612
  // one synchronous pass: back to what the author wrote, then filled
@@ -590,37 +691,33 @@ export function mount(options) {
590
691
  };
591
692
  let queue = guarded();
592
693
  const refresh = (known) => (queue = queue.then(() => guarded(known)));
694
+ /** Preview is left: at once on the page, then one fill — unless a fill that began after the exit already committed. */
695
+ const exit = () => {
696
+ endPreview();
697
+ drop();
698
+ const after = generation;
699
+ return (queue = queue.then(() => (committed >= after && last !== null ? last : guarded())));
700
+ };
593
701
  const onClick = (event) => {
594
702
  const target = event.target;
595
703
  if (!target?.closest?.(`[${P}end-preview]`))
596
704
  return;
597
705
  event.preventDefault();
598
- endPreview();
599
- void refresh();
706
+ void exit();
600
707
  };
601
708
  doc.addEventListener("click", onClick);
602
- let stopWatching = null;
603
- if (options.live) {
604
- const interval = typeof options.live === "number" ? options.live : undefined;
605
- // drafts don't move with releases: a tab in preview doesn't watch
606
- void queue.then((report) => {
607
- if (!report.preview && stopWatching === null)
608
- stopWatching = client.watch((next) => void refresh(next.release), { interval });
609
- });
610
- }
611
709
  return {
612
710
  ready: queue,
613
711
  get report() {
614
712
  return last;
615
713
  },
616
714
  refresh: () => refresh(),
617
- endPreview: () => {
618
- endPreview();
619
- return refresh();
620
- },
715
+ endPreview: exit,
621
716
  stop: () => {
717
+ stopped = true;
622
718
  stopWatching?.();
623
719
  stopWatching = () => { };
720
+ clearTimeout(expiry);
624
721
  doc.removeEventListener("click", onClick);
625
722
  },
626
723
  client,
package/dist/url.js CHANGED
@@ -49,7 +49,15 @@ export function fillTemplate(template, base, lookup) {
49
49
  failures.push({ ok: false, reason: "empty", path: segments.join(".") });
50
50
  return "";
51
51
  }
52
- return encodeURIComponent(String(value));
52
+ try {
53
+ return encodeURIComponent(String(value));
54
+ }
55
+ catch {
56
+ // a string that isn't well-formed (a lone surrogate — JSON allows it) can't be encoded:
57
+ // this place is refused, the rest of the page fills
58
+ failures.push({ ok: false, reason: "unsafe-url", path: segments.join(".") });
59
+ return "";
60
+ }
53
61
  });
54
62
  if (failures[0])
55
63
  return failures[0];
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** The package's version — what the banner of the single file and
2
2
  `Mapled.version` say. Kept equal to package.json by version.test.ts. */
3
- export declare const VERSION = "0.1.0";
3
+ export declare const VERSION = "0.1.1";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** The package's version — what the banner of the single file and
2
2
  `Mapled.version` say. Kept equal to package.json by version.test.ts. */
3
- export const VERSION = "0.1.0";
3
+ export const VERSION = "0.1.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapled/vanilla",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The browser runtime of Mapled, the hosted headless CMS for sites built with AI — published content in a plain HTML site: one script tag and data-mapled attributes, no framework and no build step.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://mapled.io",
@@ -41,7 +41,7 @@
41
41
  "typecheck": "tsc --noEmit -p tsconfig.json"
42
42
  },
43
43
  "dependencies": {
44
- "@mapled/client": "^0.1.0"
44
+ "@mapled/client": "^0.1.1"
45
45
  },
46
46
  "devDependencies": {
47
47
  "esbuild": "^0.28.2",