@mapled/vanilla 0.1.0 → 0.2.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.2.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>
@@ -87,7 +87,7 @@ The key is the project's **delivery key** (Mapled: Integrations → Your site).
87
87
  </article>
88
88
  ```
89
89
 
90
- `post.html?slug=hello-world` shows the post whose slug field is `hello-world`. `data-mapled-slug="about-us"` names the record in the page instead. Tell Mapled the page's address as `/post.html?slug=[slug]` in the site manifest (with a `route_param` binding on the slug field), and **Preview** in the record's editor opens the right page.
90
+ `post.html?slug=hello-world` shows the post whose slug field is `hello-world`. `data-mapled-slug="about-us"` names the record in the page instead. Tell Mapled the page's address as `/post.html?slug=[slug]` in the site manifest (with a `route_param` binding on the slug field) — `npx @mapled/cli scan --write` writes it from the attributes — and **Preview** in the record's editor opens the right page.
91
91
 
92
92
  ### Forms
93
93
 
@@ -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,11 +129,11 @@ 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
 
136
- Nothing to set up in the page. **Preview** in Mapled opens the page with a one-time token — `https://your-site/post.html?slug=hello&mapled-preview=mpv_…` — and the script, before its first read, takes the token out of the address bar, trades it for a draft session and keeps the session for the tab. The page shows drafts until the tab closes or the session ends, and `<html>` carries `data-mapled-preview` meanwhile:
136
+ Nothing to set up in the page. **Preview** in Mapled opens the page with a one-time token — `https://your-site/post.html?slug=hello&mapled-preview=mpv_…` — and the script, before its first read, takes the token out of the address bar, trades it for a draft session and keeps the session for the tab. The page shows drafts until the tab closes or the session ends, and `<html>` carries `data-mapled-preview` meanwhile; a form posted from that tab is filed as a test submission — not counted, nobody notified, no workflow started:
137
137
 
138
138
  ```html
139
139
  <!-- preview-bar.html -->
@@ -143,11 +143,11 @@ Nothing to set up in the page. **Preview** in Mapled opens the page with a one-t
143
143
  </style>
144
144
  ```
145
145
 
146
- Mapled has to know where the site lives and that it renders in the browser: the site manifest's `framework` is `"plain-html"` (your AI agent's `push_site_manifest`, or `npx @mapled/cli bindings push`) — or the project was created as plain HTML — and **Production domain** in Project settings holds the site's public address (an agent sets it with `set_site_url`). `npx @mapled/cli doctor` checks all of it, the script tag's version included.
146
+ Mapled has to know where the site lives and that it renders in the browser: the site manifest's `framework` is `"plain-html"` (your AI agent's `push_site_manifest`, or `npx @mapled/cli scan --write` and `npx @mapled/cli bindings push` — the scan reads the pages' attributes into the manifest) — or the project was created as plain HTML — and **Production domain** in Project settings holds the site's public address (an agent sets it with `set_site_url`). `npx @mapled/cli doctor` checks all of it, the script tag's version included.
147
147
 
148
148
  ## Live updates
149
149
 
150
- A publish shows when the page is loaded again. To follow publishes while a page is open, add `data-mapled-live` to the script tag — `data-mapled-live="30"` for the seconds between checks (60 by default, 15 at least). A check is a request of the delivery key's budget (1,200 a minute), made only while the tab is visible; a quiet one costs next to nothing.
150
+ A publish shows when the page is loaded again. To follow publishes while a page is open, add `data-mapled-live` to the script tag — `data-mapled-live="30"` for the seconds between checks (60 by default, 15 at least). A check is a request of the delivery key's budget (1,200 a minute), made only while the tab is visible; a quiet one costs next to nothing. The page knows the release it filled from, and the watch starts there: a publish that landed between the fill and the first check, or while a tab opened in the background waited to be shown, fills the page at once — and a page left as written because Mapled was out of reach fills itself from the first release the watch hears.
151
151
 
152
152
  ## What content can and can't do to the page
153
153
 
@@ -172,13 +172,13 @@ const report = await page.ready;
172
172
  if (report.state === "fallback") console.info("Showing the page as written.");
173
173
  ```
174
174
 
175
- `mount({ key, apiUrl?, root?, live?, fetch? })` answers `{ ready, report, refresh(), endPreview(), stop(), client }` — `client` is the [`@mapled/client`](https://www.npmjs.com/package/@mapled/client) the page reads through, for reads of your own. The script tag does the same from its attributes (`data-mapled-key`, `data-mapled-api`, `data-mapled-live`) and leaves the result at `Mapled.page`; a tag without a key only defines `Mapled.mount`. `VERSION` is the package's version, `Mapled.version` in a page.
175
+ `mount({ key, apiUrl?, locale?, root?, live?, fetch? })` answers `{ ready, report, refresh(), endPreview(), stop(), client }` — `client` is the [`@mapled/client`](https://www.npmjs.com/package/@mapled/client) the page reads through, for reads of your own. The script tag does the same from its attributes (`data-mapled-key`, `data-mapled-api`, `data-mapled-live`, `data-mapled-locale`) and leaves the result at `Mapled.page`; a tag without a key only defines `Mapled.mount`. `VERSION` is the package's version, `Mapled.version` in a page.
176
176
 
177
177
  ## Every attribute
178
178
 
179
179
  | Attribute | On | Says |
180
180
  |---|---|---|
181
- | `data-mapled-key`, `data-mapled-api`, `data-mapled-live` | the script tag | the delivery key; another API origin; follow publishes |
181
+ | `data-mapled-key`, `data-mapled-api`, `data-mapled-live`, `data-mapled-locale` | the script tag | the delivery key; another API origin; follow publishes; read in one of the project's languages (`data-mapled-locale="ru"` — a translated field shows in it, or in the first language of the project's fallback chain that has a value) |
182
182
  | `data-mapled-bind` | an element | the path whose value fills it |
183
183
  | `data-mapled-format` | with `data-mapled-bind` | `text` (default), `markdown`, `date`, `datetime`, `number` |
184
184
  | `data-mapled-width` | an `<img>` | the width of the picture to ask for, 16–4096 |
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.2.1 | MIT | https://mapled.io */
2
+ "use strict";(()=>{var Ct=Object.defineProperty;var Lt=(e,t,n)=>t in e?Ct(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var be=(e,t,n)=>Lt(e,typeof t!="symbol"?t+"":t,n);var we="mapled-preview",ie="mapled:preview",Nt=/^mpv_[A-Za-z0-9]{16,96}$/,Ze=/^mps_[A-Za-z0-9]{16,96}$/,Ve=new WeakMap,Ut=4e3;function ke(){if(typeof window>"u"||typeof document>"u")return null;try{let e=window.sessionStorage,t=Ve.get(window);return t||Ve.set(window,t={memory:null,exchanging:null,epoch:0}),{location:window.location,history:window.history,sessionStorage:e,page:t}}catch{return null}}function It(e){try{let t=e.getItem(ie);if(!t)return null;let n=JSON.parse(t),r=typeof n?.expiresAt=="string"?Date.parse(n.expiresAt):NaN;return typeof n?.draftToken!="string"||!Ze.test(n.draftToken)||!(r>Date.now())?(e.removeItem(ie),null):{draftToken:n.draftToken,expiresAt:n.expiresAt}}catch{return null}}function K(e){let t=It(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 B(){let e=ke();return e?K(e):null}function Ye(e){let t;try{t=new URL(e.location.href)}catch{return null}let n=t.searchParams.get(we);if(n===null)return null;t.searchParams.delete(we);try{e.history.replaceState(e.history.state,"",`${t.pathname}${t.search}${t.hash}`)}catch{}return n}function Se(){let e=ke();if(e){e.page.memory=null,e.page.epoch++,e.page.exchanging=null,Ye(e);try{e.sessionStorage.removeItem(ie)}catch{}}}function Je(e={}){let t=ke();if(!t)return Promise.resolve(null);let n=Ye(t);if(n===null)return t.page.exchanging?t.page.exchanging.done:Promise.resolve(K(t));if(!Nt.test(n))return Promise.resolve(K(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(/\/+$/,""),o=e.fetch??fetch,c=++t.page.epoch,a=(async()=>{try{let i=await o(`${r}/v1/delivery/preview/exchange`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({token:n}),cache:"no-store"});if(i.ok){let p=await i.json();if(typeof p.draftToken!="string"||typeof p.expiresAt!="string"||!Ze.test(p.draftToken)||!(Date.parse(p.expiresAt)>Date.now())||t.page.epoch!==c)return K(t);let d={draftToken:p.draftToken,expiresAt:p.expiresAt};t.page.memory=d;try{t.sessionStorage.setItem(ie,JSON.stringify(d))}catch{}return d}if(i.status===401&&t.page.epoch===c){let p=await i.json().catch(()=>null),d=p?.error?.projectId;if(t.page.epoch===c&&p?.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(l=>setTimeout(l,Ut)),K(t)}return K(t)}catch{return K(t)}})(),f={token:n,done:a};return t.page.exchanging=f,a.then(()=>{t.page.exchanging===f&&(t.page.exchanging=null)}),a}async function Qe(e){return(await Je(e))?.draftToken??null}function Ae(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}}var Dt=1e4;function Ft(e,t){let n=typeof document>"u"?void 0:globalThis.performance?.timeOrigin;if(n===void 0)return!1;let r=Date.parse(t.get("date")??""),s=Number.isNaN(r)?0:r+(Number(t.get("age"))||0)*1e3-Date.now();return Date.parse(e)>n+s-Dt}function et(e,t){return(n,r)=>{if(e!==void 0)return e;let s=t?.();return s!==void 0?s:Ft(n.publishedAt,r)?null:n.release}}function tt(e,t,n){let r=typeof e.key=="string"&&e.key.length>0;if(!r&&!e.endpoint)throw new Error("Mapled: watchRelease needs an endpoint or a delivery key.");let s=r?`${(e.apiUrl??"https://api.mapled.io").replace(/\/+$/,"")}/v1/delivery/release`:e.endpoint,o=r?{accept:"application/json","x-mapled-key":e.key}:{accept:"application/json"},c=(r?Math.max(15,e.interval??60):Math.max(2,e.interval??10))*1e3,a=e.fetch??fetch,f=typeof document>"u"?null:document,i,p=null,d=0,l=null,g=0,S=!1,x,P=null,b=()=>!f||f.visibilityState!=="hidden",C=()=>{S||!b()||(x=setTimeout(L,Math.min(c*2**g,3e5)))};async function L(){if(S||P)return;let N=new AbortController;P=N;let U=null;try{let G=await a(s,{cache:"no-cache",headers:o,signal:N.signal}),O=G.ok?Ae(await G.json()):void 0;if(S)return;O===void 0?g+=1:(g=0,i===void 0&&(i=O?t(O,G.headers):null),O&&O.release>(p?.release??0)&&(p=O),O&&O.release>(i??0)?(U={next:O,previous:i},i=O.release,d=O.release,l=null):O&&l!==null&&typeof i=="number"&&O.release>=i&&i>d&&(U={next:O,previous:l},d=i,l=null))}catch{if(S)return;g+=1}finally{P===N&&(P=null)}C(),U&&e.onPublish(U.next,U.previous)}let $=()=>{clearTimeout(x),b()&&L()};f?.addEventListener("visibilitychange",$);let z=n?.(N=>{if(S||typeof i!="number"||N>=i||i<=d||(l=l===null?N:Math.min(l,N),p===null||p.release<i))return;d=i;let U=l;l=null,e.onPublish(p,U)});return b()&&L(),()=>{S=!0,clearTimeout(x),P?.abort(),z?.(),f?.removeEventListener("visibilitychange",$)}}function nt(e){let t={};return e.forEach((n,r)=>{typeof n!="string"||r in t||(t[r]=n)}),t}async function ve(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?nt(new FormData(t)):typeof FormData<"u"&&t instanceof FormData?nt(t):{...t},o=n.page??(typeof window<"u"&&typeof document<"u"?window.location.pathname:void 0),c={...s};n.consent&&(c._consent=n.consent),o&&c._page===void 0&&(c._page=o),n.test&&(c._test=!0);let a=B()?.draftToken,f={"content-type":"application/json","x-mapled-key":n.key};a&&(f["x-mapled-draft"]=a);let i;try{i=await(n.fetch??fetch)(`${r}/v1/delivery/forms/${encodeURIComponent(e)}`,{method:"POST",headers:f,body:JSON.stringify(c)})}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 p=`The submission wasn't accepted (${i.status}).`,d;try{let l=await i.json();l.error?.message&&(p=l.error.message),typeof l.error?.code=="string"&&(d=l.error.code)}catch{}return{ok:!1,status:i.status,code:d,message:p}}var Re=/^[a-z0-9][a-z0-9-]{0,63}$/,rt=new Set;function _t(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"||!Re.test(n)))for(let[s,o]of Object.entries(r)){if(typeof o!="string"||!Re.test(s)||!Re.test(o))continue;let c=`${n}.${s}`;rt.has(c)||(rt.add(c),console.warn(`[mapled] \u201C${s}\u201D in \u201C${n}\u201D was renamed to \u201C${o}\u201D. The old key keeps working until its alias is removed in Mapled \u2014 use \u201C${o}\u201D instead.`))}}}function it(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 W=class extends Error{constructor(n,r,s){super(r);be(this,"status");be(this,"code");this.name="MapledError",this.status=n,this.code=s}},st=e=>Number.isInteger(e)&&e>=1,ot=()=>new Error("Mapled: release must be a positive whole number.");function at(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&&!st(e.release))throw ot();let n=(d,l)=>(e.fetch??fetch)(d,l),r,s=new Set;async function o(){return e.draft===null?null:typeof e.draft=="string"?e.draft||null:typeof e.draft=="function"?await e.draft()||null:Qe({apiUrl:t,appUrl:e.appUrl,fetch:e.fetch})}async function c(d){let l=`Mapled request failed (${d.status}).`,g;try{let S=await d.json();S.error?.message&&(l=S.error.message),typeof S.error?.code=="string"&&(g=S.error.code)}catch{}return new W(d.status,l,g)}async function a(d,l,g){let S=await o(),x=g.release??e.release;if(x!==void 0&&!st(x))throw ot();x!==void 0&&!S&&l.set("release",String(x));let P=g.locale||e.locale;P&&l.set("locale",P);let b=l.toString(),C=await n(`${t}${d}${b?`?${b}`:""}`,{headers:S?{"x-mapled-key":e.key,"x-mapled-draft":S}:{"x-mapled-key":e.key},...S?{cache:"no-store"}:{},...g.signal?{signal:g.signal}:{}});if(!C.ok)throw await c(C);let L=await C.json();if(!S){let $=Number(C.headers.get("x-mapled-release"));if(Number.isInteger($)&&$>=1){r=r===void 0?$:Math.min(r,$);for(let z of s)Promise.resolve().then(()=>z($))}}return _t(L),L}let f=(d,l)=>(l.expand?.length&&d.set("expand",l.expand.join(",")),l.fields?.length&&d.set("fields",l.fields.join(",")),d),i=async(d,l)=>{try{return(await a(d,f(new URLSearchParams,l),l)).record}catch(g){if(g instanceof W&&g.status===404&&g.code!=="RELEASE_NOT_FOUND")return null;throw g}};return{async getRecords(d,l={}){let g=new URLSearchParams;for(let[S,x]of Object.entries(l.filter??{}))if(x!==null&&typeof x=="object")for(let[P,b]of Object.entries(x))b!==void 0&&g.set(`filter[${S}][${P}]`,Array.isArray(b)?b.join(","):String(b));else g.set(`filter[${S}]`,String(x));return l.sort&&g.set("sort",l.sort),l.limit!==void 0&&g.set("limit",String(l.limit)),l.offset!==void 0&&g.set("offset",String(l.offset)),f(g,l),a(`/v1/delivery/collections/${encodeURIComponent(d)}/records`,g,l)},getRecord(d,l,g={}){return i(`/v1/delivery/collections/${encodeURIComponent(d)}/records/${encodeURIComponent(l)}`,g)},getRecordBySlug(d,l,g={}){return i(`/v1/delivery/collections/${encodeURIComponent(d)}/records/by-slug/${encodeURIComponent(l)}`,g)},getSingle(d,l={}){return i(`/v1/delivery/singles/${encodeURIComponent(d)}`,l)},async isPreview(){return await o()!==null},watch(d,l={}){return tt({key:e.key,apiUrl:t,interval:l.interval,onPublish:d,fetch:e.fetch},et(l.from,()=>r),g=>(s.add(g),()=>{s.delete(g)}))},async getRelease(d={}){let l=await n(`${t}/v1/delivery/release`,{headers:{"x-mapled-key":e.key},cache:"no-cache",...d.signal?{signal:d.signal}:{}});if(!l.ok)throw await c(l);let g=Ae(await l.json());if(g===void 0)throw new Error("Mapled: the release pointer didn't come back as one \u2014 check the API origin.");return g}}}var jt=/^[a-z0-9][a-z0-9_-]{0,63}$/;function Z(e){if(typeof e!="string")return null;let t=e.trim().split(".");if(t.length>8)return null;for(let n of t)if(!jt.test(n))return null;return t}var ae=(e,t)=>e!==null&&typeof e=="object"&&!Array.isArray(e)&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0;function Te(e,t){let n=e.data,r=e.expanded;for(let s=0;s<t.length;s++){let o=t[s],c=s<t.length-1?ae(r,o):void 0;if(c!==void 0){if(c===null||Array.isArray(c))return;n=ae(c,"data"),r=ae(c,"expanded");continue}if(n=ae(n,o),r=void 0,n===void 0)return}return n}var Y=e=>e==null||e===""||Array.isArray(e)&&e.length===0;function Ee(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 Kt=new Set(["http:","https:","mailto:","tel:"]),Bt=new Set(["http:","https:"]),Ht=2048;function H(e,t,n){if(typeof e!="string"||e.length>Ht)return null;let r;try{r=new URL(e,t)}catch{return null}return!(n==="link"?Kt:Bt).has(r.protocol)||r.username!==""||r.password!==""?null:r.href}var qt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,lt=e=>typeof e=="string"&&qt.test(e);function ut(e,t,n){let r=[],s=e.replace(/\{([^{}]*)\}/g,(c,a)=>{let f=Z(a);if(!f)return r.push({ok:!1,reason:"bad-path",path:a.trim().slice(0,80)}),"";let i=n(f);if(typeof i!="string"&&typeof i!="number"||i==="")return r.push({ok:!1,reason:"empty",path:f.join(".")}),"";try{return encodeURIComponent(String(i))}catch{return r.push({ok:!1,reason:"unsafe-url",path:f.join(".")}),""}});if(r[0])return r[0];let o=H(s,t,"link");return o===null?{ok:!1,reason:"unsafe-url",path:e.slice(0,80)}:{ok:!0,url:o}}var zt=1e5,dt=8,ft=2048,Wt="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",ct={amp:"&",lt:"<",gt:">",quot:'"',apos:"'",nbsp:"\xA0",copy:"\xA9",reg:"\xAE",trade:"\u2122",mdash:"\u2014",ndash:"\u2013",hellip:"\u2026",laquo:"\xAB",raquo:"\xBB"};function pt(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"),o={doc:t,base:n};if(s.length>zt){for(let c of s.split(/\n{2,}/))c.trim()!==""&&(M(o,"p",r).textContent=c.trim());return r}return Ce(o,s.split(`
4
+ `),r,0),r}function M(e,t,n){let r=e.doc.createElement(t);return n.appendChild(r),r}var xe=e=>e.trim()==="",Q=e=>e.length-e.trimStart().length;function mt(e){let t=Q(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(),o=s.length;for(;o>0&&s[o-1]==="#";)o--;return o<s.length&&(o===0||s[o-1]===" ")&&(s=s.slice(0,o).trim()),{level:n,text:s}}function $e(e){if(Q(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 Pe(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 J(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 Me=e=>/^ {0,3}>/.test(e);function Xt(e){if(mt(e)!==null||Pe(e)!==null||Me(e)||$e(e))return!0;let t=J(e);return t!==null&&t.rest!==""&&(!t.ordered||t.start===1)}function Ce(e,t,n,r){if(r>=dt){let o=t.join(`
5
+ `).trim();o!==""&&(M(e,"p",n).textContent=o);return}let s=0;for(;s<t.length;){let o=t[s];if(xe(o)){s++;continue}let c=Pe(o);if(c){let p=[],d=Q(o);for(s++;s<t.length;){let l=t[s],g=Pe(l);if(g&&g.mark===c.mark&&g.size>=c.size&&l.trim().length===g.size)break;p.push(l.slice(Math.min(d,Q(l)))),s++}s++,M(e,"code",M(e,"pre",n)).textContent=p.length>0?`${p.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=mt(o);if(a){ue(e,a.text,M(e,`h${a.level}`,n),r),s++;continue}if($e(o)){M(e,"hr",n),s++;continue}if(Me(o)){let p=[];for(;s<t.length&&Me(t[s]);)p.push(t[s].replace(/^ {0,3}> ?/,"")),s++;Ce(e,p,M(e,"blockquote",n),r+1);continue}let f=J(o);if(f){s=Gt(e,t,s,f,n,r);continue}let i=[o.trimStart()];for(s++;s<t.length&&!xe(t[s])&&!Xt(t[s]);)i.push(t[s].trimStart()),s++;ue(e,i.join(`
8
+ `),M(e,"p",n),r)}}function Gt(e,t,n,r,s,o){let c=M(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 i=J(t[n]);if(!i||i.ordered!==r.ordered||i.indent!==r.indent||$e(t[n]))break;let p=i.indent+i.width,d=[i.rest];n++;let l=!1;for(;n<t.length;){let g=t[n];if(xe(g)){l=!0,d.push(""),n++;continue}if(Q(g)<p)break;l&&d.some(S=>S!=="")&&!J(g.slice(p))&&(f=!0),l=!1,d.push(g.slice(p)),n++}for(;d.length>0&&d[d.length-1]==="";)d.pop();if(l&&n<t.length){let g=J(t[n]);g&&g.ordered===r.ordered&&g.indent===r.indent&&(f=!0)}a.push({lines:d,el:M(e,"li",c)})}for(let i of a)if(Ce(e,i.lines,i.el,o+1),!f){for(let p of Array.from(i.el.childNodes))if(p.nodeName==="P"){for(;p.firstChild;)i.el.insertBefore(p.firstChild,p);i.el.removeChild(p)}}return n}var Le=e=>e===void 0||e===" "||e===`
9
+ `,gt=e=>e!==void 0&&/[\p{L}\p{N}]/u.test(e);function le(e,t,n,r,s=""){let o=Math.min(e.length,r);for(let c=n;c<o;c++){if(e[c]===t)return c;if(s.includes(e[c]))return-1}return-1}function ee(e,t,n){let r=t;for(;e[r]===n;)r++;return r}function ht(e,t){if(e[t]==="\\")return t+2;if(e[t]==="`"){let n=ee(e,t,"`"),r=yt(e,n,n-t);return r===-1?n:r+(n-t)}return-1}function yt(e,t,n){let r=e.indexOf("`",t);for(;r!==-1;){let s=ee(e,r,"`");if(s-r===n)return r;r=e.indexOf("`",s)}return-1}function Vt(e,t,n){let r=n[0],s=t;for(;s<e.length;){let o=ht(e,s);if(o!==-1){s=o;continue}if(e[s]!==r){s++;continue}let c=ee(e,s,r),a=c-s;if((n.length===1?a===1||a>=3:a>=n.length)&&s>t&&!Le(e[s-1])&&(r!=="_"||!gt(e[c])))return c-n.length;s=c}return-1}function Zt(e,t){let n=le(e,";",t+1,t+34,`
10
+ &`);if(n===-1)return null;let r=e.slice(t+1,n);if(r[0]==="#"){let o=r[1]==="x"||r[1]==="X",c=r.slice(o?2:1);if(!(o?/^[0-9a-fA-F]{1,6}$/:/^[0-9]{1,7}$/).test(c))return null;let a=parseInt(c,o?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(ct,r)?ct[r]:void 0;return s===void 0?null:{char:s,end:n+1}}var bt=e=>e.replace(/\\([!-/:-@[-`{-~])/g,"$1");function Yt(e,t){if(e[t]!=="(")return null;let n=Math.min(e.length,t+ft+1024),r=t+1;for(;r<n&&Le(e[r])&&e[r]!==void 0;)r++;let s="";if(e[r]==="<"){let c=le(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 o=e[r];if(o==='"'||o==="'"||o==="("){let c=le(e,o==="("?")":o,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:bt(s),end:r+1}}function Oe(e,t,n=!1){let r=t+1;for(;r<e.length;){let o=ht(e,r);if(o!==-1){r=o;continue}if(!n&&e[r]==="!"&&e[r+1]==="["){let c=Oe(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=Yt(e,r+1);return s?{label:e.slice(t+1,r),address:s.address,end:s.end}:null}var Jt=/^(?:[a-z][a-z0-9+.-]{1,31}:[^\s<>]*|[^\s<>@]+@[^\s<>@]+\.[^\s<>@]+)$/i;function ue(e,t,n,r){if(r>=dt){n.appendChild(e.doc.createTextNode(t));return}let s="",o=()=>{s!==""&&n.appendChild(e.doc.createTextNode(s)),s=""},c=new Set,a=0;for(;a<t.length;){let f=t[a];if(f==="\\"){let i=t[a+1];if(i===`
15
+ `)for(o(),M(e,"br",n),a+=2;t[a]===" ";)a++;else i!==void 0&&Wt.includes(i)?(s+=i,a+=2):(s+=f,a++);continue}if(f===`
16
+ `){let i=s.endsWith(" "),p=s.length;for(;p>0&&s[p-1]===" ";)p--;for(s=s.slice(0,p),i?(o(),M(e,"br",n)):s+=`
17
+ `,a++;t[a]===" ";)a++;continue}if(f==="`"){let i=ee(t,a,"`"),p=yt(t,i,i-a);if(p===-1){s+=t.slice(a,i),a=i;continue}let d=t.slice(i,p).replace(/\n/g," ");d.length>1&&d.startsWith(" ")&&d.endsWith(" ")&&d.trim()!==""&&(d=d.slice(1,-1)),o(),M(e,"code",n).textContent=d,a=p+(i-a);continue}if(f==="!"&&t[a+1]==="["){let i=Oe(t,a+1);if(i){let p=bt(i.label),d=H(i.address.trim(),e.base,"media");if(d===null)s+=p;else{o();let l=M(e,"img",n);l.setAttribute("src",d),l.setAttribute("alt",p),l.setAttribute("loading","lazy")}a=i.end;continue}}if(f==="["){let i=Oe(t,a);if(i){let p=H(i.address.trim(),e.base,"link");o();let d=p===null?n:M(e,"a",n);p!==null&&d.setAttribute("href",p),ue(e,i.label,d,r+1),a=i.end;continue}}if(f==="<"){let i=le(t,">",a+1,a+ft,`
18
+ <`),p=i===-1?null:t.slice(a+1,i);if(p!==null&&Jt.test(p)){let d=H(p.includes(":")?p:`mailto:${p}`,e.base,"link");if(d!==null){o();let l=M(e,"a",n);l.setAttribute("href",d),l.textContent=p,a=i+1;continue}}}if(f==="&"){let i=Zt(t,a);if(i){s+=i.char,a=i.end;continue}}if(f==="*"||f==="_"||f==="~"){let i=ee(t,a,f),p=i-a,d=!Le(t[i])&&(f!=="_"||!gt(t[a-1])),l=f==="~"?p>=2?[["~~",["del"]]]:[]:[...p>=3?[[f.repeat(3),["em","strong"]]]:[],...p>=2?[[f.repeat(2),["strong"]]]:[],[f,["em"]]],g=!1;if(d)for(let[S,x]of l){if(c.has(S))continue;let P=a+S.length,b=Vt(t,P,S);if(b===-1){c.add(S);continue}if(b===P)continue;o();let C=n;for(let L of x)C=M(e,L,C);ue(e,t.slice(P,b),C,r+1),a=b+S.length,g=!0;break}g||(s+=t.slice(a,i),a=i);continue}s+=f,a++}o()}var Qt="http://www.w3.org/1999/xhtml",en=new Set(["script","style","iframe","frame","frameset","object","embed","applet","base","link","meta","template","noscript"]),ce={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"}},de=e=>e.namespaceURI===Qt,te=e=>!en.has(e.localName.toLowerCase());function Ne(e,t){if(!te(e))return"refused-element";let n=Ee(t);return n===null?"type":(e.textContent=n,null)}function wt(e,t,n){return!te(e)||!de(e)?"refused-element":typeof t!="string"?"type":(e.replaceChildren(pt(t,e.ownerDocument,n.base)),null)}function kt(e,t,n){return typeof e!="string"?null:lt(e)?it(e,{...t.apiUrl?{apiUrl:t.apiUrl}:{},...n?{width:n}:{}}):H(e,t.base,"media")}function St(e,t,n,r){if(!de(e)||e.localName!=="img")return"refused-element";if(typeof t!="string")return"type";let s=kt(t,n,r);return s===null?"unsafe-url":(e.removeAttribute("srcset"),e.setAttribute("src",s),null)}function At(e,t,n,r,s){let o=t.toLowerCase(),c=Object.prototype.hasOwnProperty.call(ce,o)?ce[o]:void 0;if(!c)return"unsupported";if(!te(e)||!de(e))return"refused-element";if(c.on!==null&&!c.on.includes(e.localName))return"unsupported";if(c.holds==="text"){let f=Ee(n);return f===null?"type":(e.setAttribute(o,f),null)}if(typeof n!="string")return"type";let a=c.holds==="media"?kt(n,r,e.localName==="img"?s:void 0):H(n,r.base,"link");return a===null?"unsafe-url":(e.setAttribute(o,a),null)}function vt(e,t){return!de(e)||e.localName!=="a"&&e.localName!=="area"?"unsupported":(e.setAttribute("href",t),null)}function X(e,t){t?e.removeAttribute("hidden"):e.setAttribute("hidden","")}var Rt=["text","markdown","date","datetime","number"],tn=/^\d{4}-\d{2}-\d{2}$/,nn=/^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;function Tt(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"||!nn.test(e))return null;let s=new Date(e);if(Number.isNaN(s.getTime()))return null;let o=tn.test(e);return new Intl.DateTimeFormat(r,{dateStyle:"long",...t==="datetime"&&!o?{timeStyle:"short"}:{},...o?{timeZone:"UTC"}:{}}).format(s)}catch{return null}}var A="data-mapled-",rn=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","locale"]),Ie=/^[a-z0-9][a-z0-9_-]{0,63}$/,sn=/^mk_[A-Za-z0-9_]{8,128}$/,on=4,an=100,ln=2;function re(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>=ln?s.length===0:s.every(o=>o===null||(Array.isArray(o)?o.every(c=>re(c,t+1)):re(o,t+1)))}var un=e=>Array.isArray(e)&&e.every(t=>re(t));function _(e){let t=e.getAttribute("id");return`${e.localName}${t&&/^[\w-]{1,40}$/.test(t)?`#${t}`:""}`}var pe=e=>(e??"").split(",").map(t=>t.trim()).filter(t=>/^[a-z0-9][a-z0-9_.-]{0,127}$/.test(t)),Et=e=>Array.from(e.children).find(t=>t.localName==="template")??null;function Ue(e,t){let n=null,r=()=>n??(n={format:"text",attrs:[],expand:[]});for(let a of Array.from(e.attributes)){if(!a.name.startsWith(A))continue;let f=a.name.slice(A.length);if(f==="bind")r().bind=a.value;else if(f.startsWith("bind-")){let i=f.slice(5);Object.prototype.hasOwnProperty.call(ce,i)?r().attrs.push([i,a.value]):t.push({path:a.value.slice(0,80),reason:"unsupported",on:`${_(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:rn.has(f)||t.push({path:a.value.slice(0,80),reason:"unsupported",on:`${_(e)}[${a.name.slice(0,60)}]`})}if(!n)return null;let s=n,o=e.getAttribute(`${A}format`);o!==null&&(Rt.includes(o)?s.format=o:t.push({path:o.slice(0,80),reason:"bad-path",on:`${_(e)}[${A}format]`}));let c=parseInt(e.getAttribute(`${A}width`)??"",10);return c>=16&&c<=4096&&(s.width=c),s.expand=pe(e.getAttribute(`${A}expand`)),s}function cn(e,t){let n={},r=e.getAttribute(`${A}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:`${_(e)}[${A}sort]`}));let s=parseInt(e.getAttribute(`${A}limit`)??"",10);s>=1&&s<=100&&(n.limit=s);let o=e.getAttribute(`${A}filter`);if(o!==null)for(let a of o.split(";")){if(a.trim()==="")continue;let f=a.indexOf("="),i=f===-1?"":a.slice(0,f).trim(),p=f===-1?"":a.slice(f+1).trim();Ie.test(i)&&p!==""&&p.length<=200?(n.filter??(n.filter={}))[i]=p:t.push({path:a.trim().slice(0,80),reason:"bad-path",on:`${_(e)}[${A}filter]`})}let c=pe(e.getAttribute(`${A}expand`));return c.length>0&&(n.expand=c),n}function fe(e,t){let n={bound:[],eaches:[],lists:[],records:[],issues:[]},r=s=>{if(s.hasAttributes()){let o=s.getAttribute(`${A}list`),c=s.getAttribute(`${A}record`),a=s.getAttribute(`${A}each`);if(o!==null||c!==null){let i=(o??c??"").trim();if(!t)n.issues.push({path:i.slice(0,80),reason:"unsupported",on:_(s)});else if(!Ie.test(i))n.issues.push({path:i.slice(0,80),reason:"bad-path",on:_(s)});else if(o!==null)n.lists.push({el:s,collection:i,options:cn(s,n.issues)});else{let p=s.getAttribute(`${A}slug-param`),d=s.getAttribute(`${A}slug`)??(p===null?null:new URLSearchParams(s.ownerDocument.location?.search??"").get(p)),l=fe(s,!0);for(let S of l.records)n.issues.push({path:S.collection,reason:"unsupported",on:_(S.el)});n.lists.push(...l.lists),n.issues.push(...l.issues);let g=Ue(s,n.issues);g&&l.bound.unshift({el:s,d:g}),n.records.push({el:s,collection:i,slug:d!==null&&d.trim()!==""&&d.length<=200?d.trim():null,expand:pe(s.getAttribute(`${A}expand`)),block:{...l,lists:[],records:[],issues:[]}})}return}if(a!==null){n.eaches.push({el:s,path:a});return}let f=Ue(s,n.issues);f&&n.bound.push({el:s,d:f})}for(let o of Array.from(s.children))r(o)};for(let s of Array.from(e.children))r(s);return n}function xt(e){let t=new Map,n=(r,s=[])=>{let o=Z(r)?.[0];if(!o)return;let c=t.get(o)??new Set;for(let a of s)c.add(a);t.set(o,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,pe(r.el.getAttribute(`${A}expand`)));return t}function ne(e,t){let n=Z(t);if(!n)return{status:"bad-path"};if(e.kind==="record")return{status:"value",value:Te(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:Te(r.value,n.slice(1))}}function De(e){if(typeof e?.key!="string"||!sn.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=at({key:e.key,apiUrl:e.apiUrl,appUrl:e.appUrl,fetch:e.fetch,...e.locale?{locale:e.locale}:{}}),s={apiUrl:e.apiUrl,base:n.baseURI},o=new Map,c=u=>{let m=o.get(u);return m||o.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 v=c(u);v.attrs.has(m)||v.attrs.set(m,u.getAttribute(m))},i=()=>{for(let[u,m]of o){m.nodes&&u.replaceChildren(...m.nodes);for(let[v,h]of m.attrs)h===null?u.removeAttribute(v):u.setAttribute(v,h)}o.clear()},p=[],d=0,l=(u,m,v)=>p.push({path:(m??"").trim().slice(0,120),reason:v,on:_(u)});function g(u,m,v){if(m.bind!==void 0){let h=ne(v,m.bind);if(h.status!=="value")l(u,m.bind,h.status);else if(!te(u))l(u,m.bind,"refused-element");else{let w=u.localName==="img";if(w?(f(u,"src"),f(u,"srcset"),f(u,"hidden")):a(u),Y(h.value))w?X(u,!1):u.textContent="",l(u,m.bind,"empty");else{let k;if(w)k=St(u,h.value,s,m.width);else if(m.format==="markdown")k=wt(u,h.value,s);else if(m.format==="text")k=Ne(u,h.value);else{let R=Tt(h.value,m.format,u.closest("[lang]")?.getAttribute("lang")??void 0);k=R===null?"type":Ne(u,R)}k?l(u,m.bind,k):d++}}}for(let[h,w]of m.attrs){let k=ne(v,w);if(k.status!=="value"){l(u,w,k.status);continue}if(f(u,h),Y(k.value)){h==="alt"?u.setAttribute("alt",""):u.removeAttribute(h),l(u,w,"empty");continue}let R=u.getAttribute(h),T=At(u,h,k.value,s,m.width);T?(R===null&&u.removeAttribute(h),l(u,w,T)):d++}for(let[h,w]of[[m.show,!0],[m.hide,!1]]){if(h===void 0)continue;let k=ne(v,h);if(k.status!=="value"){l(u,h,k.status);continue}f(u,"hidden");let R=!Y(k.value)&&k.value!==!1;X(u,R===w),d++}if(m.link!==void 0){let h=[],w=ut(m.link,s.base,k=>{let R=ne(v,k.join("."));if(R.status==="value")return R.value;h.push(R.status)});if(h[0])l(u,m.link,h[0]);else if(!w.ok)l(u,w.path,w.reason);else{f(u,"href");let k=vt(u,w.url);k?l(u,m.link,k):d++}}}function S(u,m,v){let h=Et(u);if(!h){l(u,"template","unsupported");return}a(u);let w=[h];for(let R of Array.from(u.children))R.hasAttribute(`${A}empty`)&&(f(R,"hidden"),X(R,m.length===0),w.push(R));let k=[];for(let R of m.slice(0,an)){let T=h.content.cloneNode(!0);x(fe(T,!1),{kind:"record",source:R},v+1),k.push(...Array.from(T.childNodes))}u.replaceChildren(...w,...k),d++}function x(u,m,v){p.push(...u.issues);for(let{el:h,d:w}of u.bound)g(h,w,m);for(let h of u.eaches){let w=ne(m,h.path);if(w.status!=="value"){l(h.el,h.path,w.status);continue}if(v>=on){l(h.el,h.path,"unsupported");continue}let k=w.value,R=Array.isArray(k)?k:Y(k)?[]:[k];if(R.some(T=>T===null||typeof T!="object"||Array.isArray(T))){l(h.el,h.path,"type");continue}R.length===0&&l(h.el,h.path,"empty"),S(h.el,R.map(T=>({data:T})),v)}}async function P(u,m){try{let v=await u();return v===null?{status:"missing"}:m(v)?{status:"ok",value:v}:{status:"failed",answered:!0}}catch(v){return v instanceof W&&v.status===404&&v.code!=="RELEASE_NOT_FOUND"?{status:"missing"}:{status:"failed"}}}let b=null,C="",L=null,$,z=!1,N=0,U=-1,G=3,O=typeof e.live=="number"?e.live:void 0;function Fe(){i(),b={state:"fallback",release:null,preview:!1,bound:0,issues:[]},t.setAttribute(`${A}state`,"fallback"),t.removeAttribute(`${A}preview`)}function _e(){N++,clearTimeout($),b?.preview&&Fe()}function Ot(){clearTimeout($);let u=B();if(!u||z)return;let m=Date.parse(u.expiresAt)-Date.now();$=setTimeout(()=>{B()===null&&_e(),ge()},Math.min(Math.max(m,0)+1,2147483647))}async function je(u,m=1){let v=b===null;v&&t.setAttribute(`${A}state`,"loading");let h=N,w=await r.isPreview().catch(()=>!1),k=w?B()?.draftToken??null:null;if(b!==null&&b.preview&&!w&&Fe(),!w&&u!==void 0&&b!==null&&b.state==="ready"&&!b.preview&&b.release!==null&&u<=b.release)return b;let R=y=>{b=y,U=h,t.setAttribute(`${A}state`,y.state),t.toggleAttribute(`${A}preview`,y.preview);let E=y.issues.filter(F=>F.reason!=="empty"),I=E.map(F=>`${F.path} (${F.reason}) on ${F.on}`).join("; ");return I!==C&&(C=I,E.length>0&&console.warn(`[mapled] ${E.length===1?"1 place":`${E.length} places`} couldn't be filled: ${I}`)),n.dispatchEvent(new CustomEvent(v?"mapled:ready":"mapled:update",{detail:y})),y.preview?Ot():(clearTimeout($),e.live&&L===null&&(L=r.watch(F=>{ge(F.release)},{interval:O,from:y.state==="ready"?y.release:null}))),y},T=null;if(!w)if(u!==void 0)T=u;else try{let y=await r.getRelease();if(y===null)return i(),R({state:"unpublished",release:null,preview:w,bound:0,issues:[]});T=y.release}catch{return b!==null&&b.state==="ready"?b:R({state:"fallback",release:null,preview:w,bound:0,issues:[]})}let D=T===null?{}:{release:T},j=fe(t,!0),We=Ue(t,j.issues);We&&j.bound.unshift({el:t,d:We});let he=new Map,ye=new Map,se=new Map,oe=[];for(let[y,E]of xt(j))oe.push(P(()=>r.getSingle(y,{...D,...E.size>0?{expand:[...E]}:{}}),re).then(I=>he.set(y,I)));for(let y of j.lists){let E=Et(y.el),I=E?[...xt(fe(E.content,!1)).keys()]:[];oe.push(P(async()=>(await r.getRecords(y.collection,{...y.options,...D,...I.length>0?{fields:I}:{}})).records,un).then(F=>ye.set(y,F)))}for(let y of j.records){if(y.slug===null){se.set(y,{status:"missing"});continue}let E=y.slug;oe.push(P(()=>r.getRecordBySlug(y.collection,E,{...D,...y.expand.length>0?{expand:y.expand}:{}}),re).then(I=>se.set(y,I)))}await Promise.all(oe);let Xe=await r.isPreview().catch(()=>!1)?B()?.draftToken??null:null;if(h!==N||Xe!==k)return m<G?je(u,m+1):(i(),R({state:"fallback",release:null,preview:Xe!==null,bound:0,issues:[]}));let Ge=[...he.values(),...ye.values(),...se.values()];if(Ge.length>0&&Ge.every(y=>y.status==="failed"&&!y.answered))return b!==null&&b.state==="ready"?b:R({state:"fallback",release:T,preview:w,bound:0,issues:[]});i(),p=[],d=0,x(j,{kind:"page",singles:he},0);for(let y of j.lists){let E=ye.get(y);E?.status==="ok"?S(y.el,E.value,0):l(y.el,y.collection,E?.status??"failed")}for(let y of j.records){let E=se.get(y);E?.status==="ok"?x(y.block,{kind:"record",source:E.value},0):l(y.el,y.collection,E?.status??"failed")}return He(),R({state:"ready",release:T,preview:w,bound:d,issues:p})}let Ke=new WeakSet,Be=new WeakSet;function He(){for(let u of Array.from(t.querySelectorAll(`form[${A}form]`)))Ke.has(u)||(Ke.add(u),u.addEventListener("submit",m=>{m.preventDefault(),$t(u)}))}async function $t(u){if(u.getAttribute(`${A}form-state`)==="sending")return;let m=(u.getAttribute(`${A}form`)??"").trim(),v=u.querySelector(`[${A}form-sent]`),h=u.querySelector(`[${A}form-failed]`),w=Array.from(u.querySelectorAll("button, input[type=submit]")).filter(D=>!D.disabled);u.setAttribute(`${A}form-state`,"sending");for(let D of w)D.disabled=!0;let k=u.querySelector(`input[type=checkbox][${A}consent]`),R=k?.checked?(k.labels?.[0]?.textContent??k.closest("label")?.textContent??"").trim().slice(0,500):"",T=Ie.test(m)?await ve(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 D of w)D.disabled=!1;u.setAttribute(`${A}form-state`,T.ok?"sent":"failed"),T.ok&&u.reset(),v&&X(v,T.ok),h&&(!T.ok&&(Be.has(h)||(h.textContent??"").trim()==="")&&(Be.add(h),h.textContent=T.message),X(h,!T.ok)),n.dispatchEvent(new CustomEvent("mapled:form",{detail:T.ok?{form:m,ok:!0}:{form:m,ok:!1,status:T.status,code:T.code}}))}He();let me=async u=>{try{return await je(u)}catch(m){return console.error(`[mapled] ${m instanceof Error?m.message:"The page couldn't be filled."}`),b??{state:"fallback",release:null,preview:!1,bound:0,issues:[]}}},V=me(),ge=u=>V=V.then(()=>me(u)),qe=()=>{Se(),_e();let u=N;return V=V.then(()=>U>=u&&b!==null?b:me())},ze=u=>{u.target?.closest?.(`[${A}end-preview]`)&&(u.preventDefault(),qe())};return n.addEventListener("click",ze),{ready:V,get report(){return b},refresh:()=>ge(),endPreview:qe,stop:()=>{z=!0,L?.(),L=()=>{},clearTimeout($),n.removeEventListener("click",ze)},client:r}}var Pt="0.2.1";var Mt={version:Pt,mount:De,page:null};window.Mapled=Mt;var q=document.currentScript;if(q instanceof HTMLScriptElement&&q.hasAttribute("data-mapled-key")){let e=q.getAttribute("data-mapled-live"),t=e===null?NaN:parseInt(e,10),n=()=>{try{Mt.page=De({key:q.getAttribute("data-mapled-key")??"",...q.getAttribute("data-mapled-api")?{apiUrl:q.getAttribute("data-mapled-api")}:{},...q.getAttribute("data-mapled-locale")?{locale:q.getAttribute("data-mapled-locale")}:{},...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-6apTHYxXrozzwFCqNU+70Z9pa/FDnhArNomcKQNWbeKRX4scjFiOc9d7wWKCOvTU
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;
@@ -56,6 +57,10 @@ export type MountOptions = {
56
57
  /** The project's delivery key — the one key that is safe in a page. */
57
58
  key: string;
58
59
  apiUrl?: string;
60
+ /** Read in this language: a translated field shows in it, or in the
61
+ first language of the project's fallback chain that has a value.
62
+ One of the project's languages (`pt_br` → `pt-BR`). */
63
+ locale?: string;
59
64
  /** Mapled's app — where an expired preview link sends the person. */
60
65
  appUrl?: string;
61
66
  /** Where to look for attributes (default: the whole document). */
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";
@@ -41,11 +41,36 @@ const P = "data-mapled-";
41
41
  /** Every attribute the runtime reads or writes, besides `bind-…`. */
42
42
  export const NAMES = new Set([
43
43
  "bind", "format", "width", "show", "hide", "link", "list", "each", "record", "slug", "slug-param", "sort", "limit", "filter", "expand", "empty",
44
- "form", "form-state", "form-sent", "form-failed", "consent", "end-preview", "state", "preview", "key", "api", "live",
44
+ "form", "form-state", "form-sent", "form-failed", "consent", "end-preview", "state", "preview", "key", "api", "live", "locale",
45
45
  ]);
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");
@@ -235,7 +260,13 @@ export function mount(options) {
235
260
  throw new Error("Mapled: @mapled/vanilla fills a page — it runs in a browser. On a server read with @mapled/client.");
236
261
  const root = options.root ?? document.documentElement;
237
262
  const doc = root.ownerDocument;
238
- const client = createClient({ key: options.key, apiUrl: options.apiUrl, appUrl: options.appUrl, fetch: options.fetch });
263
+ const client = createClient({
264
+ key: options.key,
265
+ apiUrl: options.apiUrl,
266
+ appUrl: options.appUrl,
267
+ fetch: options.fetch,
268
+ ...(options.locale ? { locale: options.locale } : {}),
269
+ });
239
270
  const sinks = { apiUrl: options.apiUrl, base: doc.baseURI };
240
271
  /** what the author wrote, for everything a run changed: the next run starts from it */
241
272
  const originals = new Map();
@@ -392,7 +423,7 @@ export function mount(options) {
392
423
  kept.push(child);
393
424
  }
394
425
  const items = [];
395
- for (const source of sources) {
426
+ for (const source of sources.slice(0, MAX_ITEMS)) {
396
427
  const clone = template.content.cloneNode(true);
397
428
  fill(compile(clone, false), { kind: "record", source }, depth + 1);
398
429
  items.push(...Array.from(clone.childNodes));
@@ -426,10 +457,13 @@ export function mount(options) {
426
457
  repeat(each.el, items.map((item) => ({ data: item })), depth);
427
458
  }
428
459
  }
429
- async function read(load) {
460
+ async function read(load, wellFormed) {
430
461
  try {
431
462
  const value = await load();
432
- return value === null ? { status: "missing" } : { status: "ok", value };
463
+ if (value === null)
464
+ return { status: "missing" };
465
+ // an answer of another shape than Mapled's is no answer: the place keeps the author's HTML
466
+ return wellFormed(value) ? { status: "ok", value } : { status: "failed", answered: true };
433
467
  }
434
468
  catch (err) {
435
469
  // an unknown collection or single is the page's mistake, not an outage
@@ -438,13 +472,64 @@ export function mount(options) {
438
472
  }
439
473
  let last = null;
440
474
  let warned = "";
441
- async function run(known) {
475
+ let stopWatching = null;
476
+ let expiry;
477
+ let stopped = false;
478
+ /** moves when preview is left: a fill that began before it commits nothing */
479
+ let generation = 0;
480
+ /** the generation of the last fill that committed: an exit's own fill is skipped when one already has */
481
+ let committed = -1;
482
+ /** how many times a fill starts over when the session changed under it */
483
+ const MAX_ATTEMPTS = 3;
484
+ const interval = typeof options.live === "number" ? options.live : undefined;
485
+ /** Preview is over — the page's own way out, or the session's end: the
486
+ page is as written again, and says so, before anything is asked of
487
+ Mapled; what is published follows when it is in hand. */
488
+ function leave() {
489
+ restore();
490
+ last = { state: "fallback", release: null, preview: false, bound: 0, issues: [] };
491
+ root.setAttribute(`${P}state`, "fallback");
492
+ root.removeAttribute(`${P}preview`);
493
+ }
494
+ /** Preview ends now, not after the fill in flight: the draft goes at
495
+ once, and whatever that fill brings back is dropped. */
496
+ function drop() {
497
+ generation++;
498
+ clearTimeout(expiry);
499
+ if (last?.preview)
500
+ leave();
501
+ }
502
+ /** The session's end is a fill of its own: no draft is shown past it —
503
+ the timer stays set through fills that fail or stall. */
504
+ function watchExpiry() {
505
+ clearTimeout(expiry);
506
+ const session = previewSession();
507
+ if (!session || stopped)
508
+ return;
509
+ const left = Date.parse(session.expiresAt) - Date.now();
510
+ expiry = setTimeout(() => {
511
+ if (previewSession() === null)
512
+ drop();
513
+ void refresh();
514
+ }, Math.min(Math.max(left, 0) + 1, 0x7fffffff));
515
+ }
516
+ async function run(known, attempt = 1) {
442
517
  const first = last === null;
443
518
  if (first)
444
519
  root.setAttribute(`${P}state`, "loading");
520
+ const mine = generation;
445
521
  const preview = await client.isPreview().catch(() => false);
522
+ // the session the drafts are read with: an answer read with another one is not this fill's
523
+ const session = preview ? (previewSession()?.draftToken ?? null) : null;
524
+ // a tab that left preview, or whose session ended, shows nothing of the drafts — before anything is asked
525
+ if (last !== null && last.preview && !preview)
526
+ leave();
527
+ // 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
528
+ if (!preview && known !== undefined && last !== null && last.state === "ready" && !last.preview && last.release !== null && known <= last.release)
529
+ return last;
446
530
  const finish = (report) => {
447
531
  last = report;
532
+ committed = mine;
448
533
  root.setAttribute(`${P}state`, report.state);
449
534
  root.toggleAttribute(`${P}preview`, report.preview);
450
535
  const loud = report.issues.filter((i) => i.reason !== "empty");
@@ -455,6 +540,16 @@ export function mount(options) {
455
540
  console.warn(`[mapled] ${loud.length === 1 ? "1 place" : `${loud.length} places`} couldn't be filled: ${text}`);
456
541
  }
457
542
  doc.dispatchEvent(new CustomEvent(first ? "mapled:ready" : "mapled:update", { detail: report }));
543
+ if (report.preview)
544
+ watchExpiry();
545
+ else {
546
+ clearTimeout(expiry);
547
+ // drafts don't move with releases: a tab watches once it shows what is published — from the release it shows
548
+ // (its reads are pinned to it), so a publish that landed between the fill and the watch's first answer, or
549
+ // while a background tab waited to be shown, is news; a page as written shows no release: the first named is
550
+ if (options.live && stopWatching === null)
551
+ stopWatching = client.watch((next) => void refresh(next.release), { interval, from: report.state === "ready" ? report.release : null });
552
+ }
458
553
  return report;
459
554
  };
460
555
  // drafts have no release; what is published is read pinned to one, so a
@@ -467,12 +562,15 @@ export function mount(options) {
467
562
  else {
468
563
  try {
469
564
  const pointer = await client.getRelease();
470
- if (pointer === null)
565
+ if (pointer === null) {
566
+ // nothing is published: the page is as written — a draft it showed goes too
567
+ restore();
471
568
  return finish({ state: "unpublished", release: null, preview, bound: 0, issues: [] });
569
+ }
472
570
  release = pointer.release;
473
571
  }
474
572
  catch {
475
- // out of reach: the page stays as it is — as written, or as last filled
573
+ // out of reach: the page stays as it is — as written, or as last filled from what is published
476
574
  return last !== null && last.state === "ready" ? last : finish({ state: "fallback", release: null, preview, bound: 0, issues: [] });
477
575
  }
478
576
  }
@@ -488,12 +586,12 @@ export function mount(options) {
488
586
  const records = new Map();
489
587
  const reads = [];
490
588
  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)));
589
+ reads.push(read(() => client.getSingle(key, { ...pin, ...(expand.size > 0 ? { expand: [...expand] } : {}) }), isRecord).then((r) => singles.set(key, r)));
492
590
  }
493
591
  for (const list of page.lists) {
494
592
  const template = templateOf(list.el);
495
593
  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)));
594
+ 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
595
  }
498
596
  for (const record of page.records) {
499
597
  if (record.slug === null) {
@@ -501,11 +599,22 @@ export function mount(options) {
501
599
  continue;
502
600
  }
503
601
  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)));
602
+ reads.push(read(() => client.getRecordBySlug(record.collection, slug, { ...pin, ...(record.expand.length > 0 ? { expand: record.expand } : {}) }), isRecord).then((r) => records.set(record, r)));
505
603
  }
506
604
  await Promise.all(reads);
605
+ // preview was left, or the session ended or was replaced, while the reads were on their way:
606
+ // what they brought is nobody's now — read again, with whatever the tab has
607
+ const now = (await client.isPreview().catch(() => false)) ? (previewSession()?.draftToken ?? null) : null;
608
+ if (mine !== generation || now !== session) {
609
+ if (attempt < MAX_ATTEMPTS)
610
+ return run(known, attempt + 1);
611
+ // the session keeps changing under the reads: show nothing of any of them — the page as written, until the next fill
612
+ restore();
613
+ return finish({ state: "fallback", release: null, preview: now !== null, bound: 0, issues: [] });
614
+ }
615
+ // 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
616
  const answers = [...singles.values(), ...lists.values(), ...records.values()];
508
- if (answers.length > 0 && answers.every((a) => a.status === "failed")) {
617
+ if (answers.length > 0 && answers.every((a) => a.status === "failed" && !a.answered)) {
509
618
  return last !== null && last.state === "ready" ? last : finish({ state: "fallback", release, preview, bound: 0, issues: [] });
510
619
  }
511
620
  // one synchronous pass: back to what the author wrote, then filled
@@ -590,37 +699,33 @@ export function mount(options) {
590
699
  };
591
700
  let queue = guarded();
592
701
  const refresh = (known) => (queue = queue.then(() => guarded(known)));
702
+ /** Preview is left: at once on the page, then one fill — unless a fill that began after the exit already committed. */
703
+ const exit = () => {
704
+ endPreview();
705
+ drop();
706
+ const after = generation;
707
+ return (queue = queue.then(() => (committed >= after && last !== null ? last : guarded())));
708
+ };
593
709
  const onClick = (event) => {
594
710
  const target = event.target;
595
711
  if (!target?.closest?.(`[${P}end-preview]`))
596
712
  return;
597
713
  event.preventDefault();
598
- endPreview();
599
- void refresh();
714
+ void exit();
600
715
  };
601
716
  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
717
  return {
612
718
  ready: queue,
613
719
  get report() {
614
720
  return last;
615
721
  },
616
722
  refresh: () => refresh(),
617
- endPreview: () => {
618
- endPreview();
619
- return refresh();
620
- },
723
+ endPreview: exit,
621
724
  stop: () => {
725
+ stopped = true;
622
726
  stopWatching?.();
623
727
  stopWatching = () => { };
728
+ clearTimeout(expiry);
624
729
  doc.removeEventListener("click", onClick);
625
730
  },
626
731
  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.2.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.2.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapled/vanilla",
3
- "version": "0.1.0",
3
+ "version": "0.2.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.2.1"
45
45
  },
46
46
  "devDependencies": {
47
47
  "esbuild": "^0.28.2",