@fluixi/head 1.0.0-alpha.50 → 1.0.0-alpha.52

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/dist/index.mjs ADDED
@@ -0,0 +1,638 @@
1
+ /*! @fluixi/head v1.0.0-alpha.52 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // src/core.ts
9
+ import { getOwner, onCleanup, createSignal } from "@fluixi/reactive/signal";
10
+ function val(v) {
11
+ return typeof v === "function" ? v() : v;
12
+ }
13
+ function robotsToString(r) {
14
+ if (typeof r === "string") return r;
15
+ const out = [];
16
+ out.push(r.index === false ? "noindex" : "index");
17
+ out.push(r.follow === false ? "nofollow" : "follow");
18
+ if (r.noarchive) out.push("noarchive");
19
+ if (r.nosnippet) out.push("nosnippet");
20
+ if (r.noimageindex) out.push("noimageindex");
21
+ if (r.maxSnippet != null) out.push(`max-snippet:${r.maxSnippet}`);
22
+ if (r.maxImagePreview) out.push(`max-image-preview:${r.maxImagePreview}`);
23
+ if (r.maxVideoPreview != null) out.push(`max-video-preview:${r.maxVideoPreview}`);
24
+ return out.join(", ");
25
+ }
26
+ function createHead() {
27
+ const sources = [];
28
+ const [version, bump] = createSignal(0);
29
+ return {
30
+ sources,
31
+ version,
32
+ push(input) {
33
+ sources.push(input);
34
+ bump((n) => n + 1);
35
+ return () => {
36
+ const i = sources.indexOf(input);
37
+ if (i !== -1) {
38
+ sources.splice(i, 1);
39
+ bump((n) => n + 1);
40
+ }
41
+ };
42
+ }
43
+ };
44
+ }
45
+ var active = null;
46
+ function setActiveHead(h) {
47
+ active = h;
48
+ }
49
+ function getActiveHead() {
50
+ return active;
51
+ }
52
+ function runWithHead(h, fn) {
53
+ const prev = active;
54
+ active = h;
55
+ try {
56
+ return fn();
57
+ } finally {
58
+ active = prev;
59
+ }
60
+ }
61
+ function useHead(input) {
62
+ const h = getActiveHead();
63
+ if (!h) {
64
+ const proc = globalThis.process;
65
+ if (proc?.env?.NODE_ENV !== "production") {
66
+ console.warn("[fluixi/head] useHead() called with no active head registry — ignored.");
67
+ }
68
+ return () => {
69
+ };
70
+ }
71
+ const dispose = h.push(input);
72
+ if (typeof window !== "undefined" && getOwner()) onCleanup(dispose);
73
+ return dispose;
74
+ }
75
+ var seo = useHead;
76
+ function djb2(s) {
77
+ let h = 5381;
78
+ for (let i = 0; i < s.length; i++) h = h * 33 ^ s.charCodeAt(i);
79
+ return (h >>> 0).toString(36);
80
+ }
81
+ function metaKey(a) {
82
+ if (a.charset != null) return "meta:charset";
83
+ if (a.property) return "meta:property:" + a.property;
84
+ if (a.name) return "meta:name:" + a.name;
85
+ if (a["http-equiv"]) return "meta:http-equiv:" + a["http-equiv"];
86
+ return "meta:" + djb2(JSON.stringify(a));
87
+ }
88
+ function pushImage(out, img) {
89
+ const o = typeof img === "string" ? { url: img } : img;
90
+ out.push({ tag: "meta", key: "meta:property:og:image:" + o.url, attrs: { property: "og:image", content: o.url } });
91
+ if (o.secureUrl) out.push({ tag: "meta", key: "meta:property:og:image:secure:" + o.url, attrs: { property: "og:image:secure_url", content: o.secureUrl } });
92
+ if (o.type) out.push({ tag: "meta", key: "meta:property:og:image:type:" + o.url, attrs: { property: "og:image:type", content: o.type } });
93
+ if (o.width != null) out.push({ tag: "meta", key: "meta:property:og:image:width:" + o.url, attrs: { property: "og:image:width", content: String(o.width) } });
94
+ if (o.height != null) out.push({ tag: "meta", key: "meta:property:og:image:height:" + o.url, attrs: { property: "og:image:height", content: String(o.height) } });
95
+ if (o.alt) out.push({ tag: "meta", key: "meta:property:og:image:alt:" + o.url, attrs: { property: "og:image:alt", content: o.alt } });
96
+ }
97
+ function expandOG(og, out) {
98
+ const m = (p, c) => {
99
+ if (c != null) out.push({ tag: "meta", key: "meta:property:og:" + p, attrs: { property: "og:" + p, content: c } });
100
+ };
101
+ m("title", og.title);
102
+ m("description", og.description);
103
+ m("type", og.type);
104
+ m("url", og.url);
105
+ m("site_name", og.siteName);
106
+ m("locale", og.locale);
107
+ for (const l of og.localeAlternate ?? []) out.push({ tag: "meta", key: "meta:property:og:locale:alt:" + l, attrs: { property: "og:locale:alternate", content: l } });
108
+ if (og.image != null) {
109
+ const imgs = Array.isArray(og.image) ? og.image : [og.image];
110
+ for (const i of imgs) pushImage(out, i);
111
+ }
112
+ if (og.video) {
113
+ const v = typeof og.video === "string" ? { url: og.video } : og.video;
114
+ m("video", v.url);
115
+ if ("type" in v && v.type) m("video:type", v.type);
116
+ if ("width" in v && v.width != null) m("video:width", String(v.width));
117
+ if ("height" in v && v.height != null) m("video:height", String(v.height));
118
+ }
119
+ if (og.audio) {
120
+ const a = typeof og.audio === "string" ? { url: og.audio } : og.audio;
121
+ m("audio", a.url);
122
+ if ("type" in a && a.type) m("audio:type", a.type);
123
+ }
124
+ if (og.article) {
125
+ const ar = og.article;
126
+ m("article:published_time", ar.publishedTime);
127
+ m("article:modified_time", ar.modifiedTime);
128
+ m("article:expiration_time", ar.expirationTime);
129
+ m("article:section", ar.section);
130
+ for (const au of [].concat(ar.author ?? [])) out.push({ tag: "meta", key: "meta:property:og:article:author:" + au, attrs: { property: "article:author", content: au } });
131
+ for (const t of [].concat(ar.tag ?? [])) out.push({ tag: "meta", key: "meta:property:og:article:tag:" + t, attrs: { property: "article:tag", content: t } });
132
+ }
133
+ if (og.book) {
134
+ const b = og.book;
135
+ m("book:isbn", b.isbn);
136
+ m("book:release_date", b.releaseDate);
137
+ for (const au of [].concat(b.author ?? [])) out.push({ tag: "meta", key: "meta:property:og:book:author:" + au, attrs: { property: "book:author", content: au } });
138
+ for (const t of [].concat(b.tag ?? [])) out.push({ tag: "meta", key: "meta:property:og:book:tag:" + t, attrs: { property: "book:tag", content: t } });
139
+ }
140
+ if (og.profile) {
141
+ const p = og.profile;
142
+ m("profile:first_name", p.firstName);
143
+ m("profile:last_name", p.lastName);
144
+ m("profile:username", p.username);
145
+ m("profile:gender", p.gender);
146
+ }
147
+ }
148
+ function expandTwitter(t, out) {
149
+ const m = (n, c) => {
150
+ if (c != null) out.push({ tag: "meta", key: "meta:name:twitter:" + n, attrs: { name: "twitter:" + n, content: c } });
151
+ };
152
+ m("card", t.card);
153
+ m("site", t.site);
154
+ m("creator", t.creator);
155
+ m("title", t.title);
156
+ m("description", t.description);
157
+ m("image", t.image);
158
+ m("image:alt", t.imageAlt);
159
+ m("player", t.player);
160
+ if (t.playerWidth != null) m("player:width", String(t.playerWidth));
161
+ if (t.playerHeight != null) m("player:height", String(t.playerHeight));
162
+ if (t.app) {
163
+ m("app:name:iphone", t.app.name);
164
+ m("app:id:iphone", t.app.idIphone);
165
+ m("app:id:ipad", t.app.idIpad);
166
+ m("app:id:googleplay", t.app.idGooglePlay);
167
+ }
168
+ }
169
+ function expandIcons(icons, out) {
170
+ const link = (key, attrs) => out.push({ tag: "link", key, attrs });
171
+ if (icons.icon != null) {
172
+ const arr = typeof icons.icon === "string" ? [{ url: icons.icon }] : icons.icon;
173
+ for (const i of arr) link("link:icon:" + i.url, { rel: "icon", href: i.url, ...i.type ? { type: i.type } : {}, ...i.sizes ? { sizes: i.sizes } : {} });
174
+ }
175
+ if (icons.apple != null) {
176
+ const arr = typeof icons.apple === "string" ? [{ url: icons.apple }] : icons.apple;
177
+ for (const i of arr) link("link:apple-touch-icon:" + i.url, { rel: "apple-touch-icon", href: i.url, ...i.sizes ? { sizes: i.sizes } : {} });
178
+ }
179
+ if (icons.mask) link("link:mask-icon", { rel: "mask-icon", href: icons.mask.url, ...icons.mask.color ? { color: icons.mask.color } : {} });
180
+ if (icons.shortcut) link("link:shortcut", { rel: "shortcut icon", href: icons.shortcut });
181
+ if (icons.msTileImage) out.push({ tag: "meta", key: "meta:name:msapplication-TileImage", attrs: { name: "msapplication-TileImage", content: icons.msTileImage } });
182
+ if (icons.msTileColor) out.push({ tag: "meta", key: "meta:name:msapplication-TileColor", attrs: { name: "msapplication-TileColor", content: icons.msTileColor } });
183
+ }
184
+ function expand(input, out, ts) {
185
+ const meta = (key, attrs) => out.push({ tag: "meta", key, attrs });
186
+ const title = val(input.title);
187
+ if (title !== void 0) ts.title = title;
188
+ if (input.titleTemplate !== void 0) ts.template = input.titleTemplate;
189
+ const lang = val(input.lang);
190
+ if (lang !== void 0) out.push({ tag: "htmlAttr", key: "html:lang", name: "lang", value: lang });
191
+ if (input.charset !== void 0) meta("meta:charset", { charset: input.charset });
192
+ if (input.viewport !== void 0) meta("meta:name:viewport", { name: "viewport", content: input.viewport });
193
+ const desc = val(input.description);
194
+ if (desc !== void 0) meta("meta:name:description", { name: "description", content: desc });
195
+ const kw = val(input.keywords);
196
+ if (kw !== void 0) meta("meta:name:keywords", { name: "keywords", content: Array.isArray(kw) ? kw.join(", ") : kw });
197
+ if (input.author !== void 0) meta("meta:name:author", { name: "author", content: input.author });
198
+ if (input.robots !== void 0) meta("meta:name:robots", { name: "robots", content: robotsToString(input.robots) });
199
+ if (input.generator !== void 0) meta("meta:name:generator", { name: "generator", content: input.generator });
200
+ if (input.applicationName !== void 0) meta("meta:name:application-name", { name: "application-name", content: input.applicationName });
201
+ if (input.referrer !== void 0) meta("meta:name:referrer", { name: "referrer", content: input.referrer });
202
+ if (input.colorScheme !== void 0) meta("meta:name:color-scheme", { name: "color-scheme", content: input.colorScheme });
203
+ const theme = val(input.themeColor);
204
+ if (theme !== void 0) meta("meta:name:theme-color", { name: "theme-color", content: theme });
205
+ const canonical = val(input.canonical);
206
+ if (canonical !== void 0) out.push({ tag: "link", key: "link:rel:canonical", attrs: { rel: "canonical", href: canonical } });
207
+ if (input.manifest !== void 0) out.push({ tag: "link", key: "link:rel:manifest", attrs: { rel: "manifest", href: input.manifest } });
208
+ if (input.base !== void 0) out.push({ tag: "base", key: "base", attrs: { href: input.base } });
209
+ if (input.verification) {
210
+ const map = { google: "google-site-verification", bing: "msvalidate.01", yandex: "yandex-verification", pinterest: "p:domain_verify" };
211
+ for (const [k, v] of Object.entries(input.verification)) {
212
+ if (v == null) continue;
213
+ const name = map[k] ?? k;
214
+ meta("meta:name:" + name, { name, content: v });
215
+ }
216
+ }
217
+ for (const a of input.alternates ?? []) out.push({ tag: "link", key: "link:alternate:hreflang:" + a.hreflang, attrs: { rel: "alternate", hreflang: a.hreflang, href: a.href } });
218
+ for (const f of input.feeds ?? []) out.push({ tag: "link", key: "link:alternate:feed:" + f.href, attrs: { rel: "alternate", type: f.type ?? "application/rss+xml", href: f.href, ...f.title ? { title: f.title } : {} } });
219
+ if (input.og) expandOG(input.og, out);
220
+ if (input.twitter) expandTwitter(input.twitter, out);
221
+ if (input.icons) expandIcons(input.icons, out);
222
+ const ld = val(input.jsonLd);
223
+ if (ld !== void 0) {
224
+ const arr = Array.isArray(ld) ? ld : [ld];
225
+ for (const obj of arr) {
226
+ const json = JSON.stringify(obj);
227
+ out.push({ tag: "script", key: "script:ldjson:" + djb2(json), attrs: { type: "application/ld+json" }, children: json });
228
+ }
229
+ }
230
+ for (const m of input.meta ?? []) {
231
+ const attrs = {};
232
+ for (const [k, v] of Object.entries(m)) if (v != null) attrs[k === "httpEquiv" ? "http-equiv" : k] = v;
233
+ out.push({ tag: "meta", key: metaKey(attrs), attrs });
234
+ }
235
+ for (const l of input.link ?? []) {
236
+ const attrs = {};
237
+ for (const [k, v] of Object.entries(l)) if (v != null) attrs[k] = v;
238
+ out.push({ tag: "link", key: "link:" + (attrs.rel ?? "") + ":" + (attrs.href ?? djb2(JSON.stringify(attrs))), attrs });
239
+ }
240
+ for (const s of input.script ?? []) {
241
+ const attrs = {};
242
+ let children;
243
+ for (const [k, v] of Object.entries(s)) {
244
+ if (v == null) continue;
245
+ if (k === "children") children = v;
246
+ else attrs[k] = v;
247
+ }
248
+ out.push({ tag: "script", key: "script:" + (attrs.src ?? djb2((children ?? "") + JSON.stringify(attrs))), attrs, children });
249
+ }
250
+ }
251
+ function applyTemplate(tpl, title) {
252
+ return typeof tpl === "function" ? tpl(title) : tpl.includes("%s") ? tpl.replace("%s", title) : tpl;
253
+ }
254
+ function resolveHead(head) {
255
+ const raw = [];
256
+ const ts = {};
257
+ for (const src of head.sources) {
258
+ const input = typeof src === "function" ? src() : src;
259
+ expand(input, raw, ts);
260
+ }
261
+ if (ts.title !== void 0) {
262
+ raw.push({ tag: "title", key: "title", children: ts.template ? applyTemplate(ts.template, ts.title) : ts.title });
263
+ }
264
+ const byKey = /* @__PURE__ */ new Map();
265
+ const htmlAttrs = {};
266
+ for (const t of raw) {
267
+ if (t.tag === "htmlAttr") {
268
+ htmlAttrs[t.name] = t.value;
269
+ continue;
270
+ }
271
+ byKey.set(t.key, t);
272
+ }
273
+ return { tags: [...byKey.values()], htmlAttrs };
274
+ }
275
+
276
+ // src/serialize.ts
277
+ function escAttr(s) {
278
+ return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
279
+ }
280
+ function escText(s) {
281
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
282
+ }
283
+ function escScript(s) {
284
+ return s.replace(/<\//g, "<\\/").replace(/<!--/g, "<\\!--");
285
+ }
286
+ var MANAGED_ATTR = "data-fh";
287
+ var KEY_ATTR = "data-fh-key";
288
+ function renderAttrs(attrs) {
289
+ let s = "";
290
+ for (const [k, v] of Object.entries(attrs)) s += ` ${k}="${escAttr(v)}"`;
291
+ return s;
292
+ }
293
+ function renderTag(t) {
294
+ switch (t.tag) {
295
+ case "title":
296
+ return `<title ${MANAGED_ATTR}>${escText(t.children)}</title>`;
297
+ case "meta":
298
+ case "link":
299
+ case "base": {
300
+ const marker = ` ${MANAGED_ATTR} ${KEY_ATTR}="${escAttr(t.key)}"`;
301
+ return `<${t.tag}${renderAttrs(t.attrs)}${marker}>`;
302
+ }
303
+ case "script": {
304
+ const marker = ` ${MANAGED_ATTR} ${KEY_ATTR}="${escAttr(t.key)}"`;
305
+ const body = t.children ? escScript(t.children) : "";
306
+ return `<script${renderAttrs(t.attrs)}${marker}>${body}<\/script>`;
307
+ }
308
+ default:
309
+ return "";
310
+ }
311
+ }
312
+ function renderHead(head) {
313
+ const { tags, htmlAttrs } = resolveHead(head);
314
+ const order = { title: 0, base: 1, meta: 2, link: 3, script: 4 };
315
+ const sorted = [...tags].sort((a, b) => (order[a.tag] ?? 9) - (order[b.tag] ?? 9));
316
+ return { headHtml: sorted.map(renderTag).join(""), htmlAttrs };
317
+ }
318
+ function renderHtmlAttrs(htmlAttrs) {
319
+ return Object.entries(htmlAttrs).map(([k, v]) => ` ${k}="${escAttr(v)}"`).join("");
320
+ }
321
+
322
+ // src/transport.ts
323
+ var RE = /<!--fh:([A-Za-z0-9+/=]+)-->/;
324
+ function b64encode(s) {
325
+ const g = globalThis;
326
+ if (g.Buffer) return g.Buffer.from(s, "utf-8").toString("base64");
327
+ return g.btoa(unescape(encodeURIComponent(s)));
328
+ }
329
+ function b64decode(s) {
330
+ const g = globalThis;
331
+ if (g.Buffer) return g.Buffer.from(s, "base64").toString("utf-8");
332
+ return decodeURIComponent(escape(g.atob(s)));
333
+ }
334
+ function encodeHeadMarker(head) {
335
+ if (!head.headHtml && Object.keys(head.htmlAttrs).length === 0) return "";
336
+ return `<!--fh:${b64encode(JSON.stringify(head))}-->`;
337
+ }
338
+ function stripHeadMarker(container) {
339
+ for (let n = container.firstChild; n; n = n.nextSibling) {
340
+ if (n.nodeType === 8 && n.data.startsWith("fh:")) {
341
+ n.parentNode?.removeChild(n);
342
+ return;
343
+ }
344
+ }
345
+ }
346
+ function extractHeadMarker(html) {
347
+ const m = html.match(RE);
348
+ if (!m) return { head: null, body: html };
349
+ let head = null;
350
+ try {
351
+ head = JSON.parse(b64decode(m[1]));
352
+ } catch {
353
+ head = null;
354
+ }
355
+ return { head, body: html.replace(m[0], "") };
356
+ }
357
+
358
+ // src/reconcile.ts
359
+ import { createRoot, createEffect, onCleanup as onCleanup2 } from "@fluixi/reactive/signal";
360
+ function setAttrs(el, attrs) {
361
+ for (const a of Array.from(el.attributes)) {
362
+ if (a.name === MANAGED_ATTR || a.name === KEY_ATTR) continue;
363
+ if (!(a.name in attrs)) el.removeAttribute(a.name);
364
+ }
365
+ for (const [k, v] of Object.entries(attrs)) if (el.getAttribute(k) !== v) el.setAttribute(k, v);
366
+ }
367
+ function createEl(t) {
368
+ const el = document.createElement(t.tag);
369
+ setAttrs(el, t.attrs);
370
+ el.setAttribute(MANAGED_ATTR, "");
371
+ el.setAttribute(KEY_ATTR, t.key);
372
+ if (t.tag === "script" && t.children != null) el.textContent = t.children;
373
+ return el;
374
+ }
375
+ function apply(tags, htmlAttrs) {
376
+ const head = document.head;
377
+ const existing = /* @__PURE__ */ new Map();
378
+ for (const el of Array.from(head.querySelectorAll(`[${MANAGED_ATTR}]`))) {
379
+ const key = el.getAttribute(KEY_ATTR);
380
+ if (el.tagName === "TITLE") continue;
381
+ if (key) existing.set(key, el);
382
+ }
383
+ let title = null;
384
+ const seen = /* @__PURE__ */ new Set();
385
+ for (const t of tags) {
386
+ if (t.tag === "title") {
387
+ title = t.children;
388
+ continue;
389
+ }
390
+ if (t.tag === "htmlAttr") continue;
391
+ seen.add(t.key);
392
+ const cur = existing.get(t.key);
393
+ if (cur && cur.tagName === t.tag.toUpperCase()) {
394
+ setAttrs(cur, t.attrs);
395
+ if (t.tag === "script" && (cur.textContent ?? "") !== (t.children ?? "")) cur.textContent = t.children ?? "";
396
+ } else {
397
+ if (cur) cur.remove();
398
+ head.appendChild(createEl(t));
399
+ }
400
+ }
401
+ for (const [key, el] of existing) if (!seen.has(key)) el.remove();
402
+ if (title != null && document.title !== title) document.title = title;
403
+ for (const [k, v] of Object.entries(htmlAttrs)) {
404
+ if (document.documentElement.getAttribute(k) !== v) document.documentElement.setAttribute(k, v);
405
+ }
406
+ }
407
+ function mountHead(head) {
408
+ return createRoot((dispose) => {
409
+ createEffect(() => {
410
+ head.version();
411
+ const { tags, htmlAttrs } = resolveHead(head);
412
+ apply(tags, htmlAttrs);
413
+ });
414
+ onCleanup2(() => {
415
+ });
416
+ return dispose;
417
+ });
418
+ }
419
+
420
+ // src/jsonld.ts
421
+ var CTX = "https://schema.org";
422
+ var clean = (o) => {
423
+ const out = {};
424
+ for (const [k, v] of Object.entries(o)) if (v !== void 0) out[k] = v;
425
+ return out;
426
+ };
427
+ var custom = (type, data = {}) => clean({ "@context": CTX, "@type": type, ...data });
428
+ var organization = (d) => custom("Organization", d);
429
+ var person = (d) => custom("Person", d);
430
+ var website = (d) => {
431
+ const { searchUrl, ...rest } = d;
432
+ return custom("WebSite", {
433
+ ...rest,
434
+ ...searchUrl ? {
435
+ potentialAction: {
436
+ "@type": "SearchAction",
437
+ target: { "@type": "EntryPoint", urlTemplate: `${searchUrl}{search_term_string}` },
438
+ "query-input": "required name=search_term_string"
439
+ }
440
+ } : {}
441
+ });
442
+ };
443
+ var webPage = (d) => custom("WebPage", d);
444
+ var searchAction = (d) => clean({ "@type": "SearchAction", target: { "@type": "EntryPoint", urlTemplate: d.target }, "query-input": d.queryInput ?? "required name=search_term_string" });
445
+ var article = (d) => custom("Article", { ...d, author: typeof d.author === "string" ? { "@type": "Person", name: d.author } : d.author });
446
+ var blogPosting = (d) => ({ ...article(d), "@type": "BlogPosting" });
447
+ var faq = (items) => custom("FAQPage", {
448
+ mainEntity: items.map((i) => ({ "@type": "Question", name: i.question, acceptedAnswer: { "@type": "Answer", text: i.answer } }))
449
+ });
450
+ var product = (d) => custom("Product", { ...d, brand: typeof d.brand === "string" ? { "@type": "Brand", name: d.brand } : d.brand });
451
+ var breadcrumb = (items) => custom("BreadcrumbList", {
452
+ itemListElement: items.map((it, i) => ({ "@type": "ListItem", position: i + 1, name: it.name, item: it.url }))
453
+ });
454
+ var videoObject = (d) => custom("VideoObject", d);
455
+ var event = (d) => custom("Event", { ...d, location: typeof d.location === "string" ? { "@type": "Place", name: d.location } : d.location });
456
+ var localBusiness = (d) => custom("LocalBusiness", d);
457
+ var softwareApplication = (d) => custom("SoftwareApplication", d);
458
+ var jsonld = {
459
+ custom,
460
+ organization,
461
+ person,
462
+ website,
463
+ webPage,
464
+ searchAction,
465
+ article,
466
+ blogPosting,
467
+ faq,
468
+ product,
469
+ breadcrumb,
470
+ videoObject,
471
+ event,
472
+ localBusiness,
473
+ softwareApplication
474
+ };
475
+
476
+ // src/components.ts
477
+ var components_exports = {};
478
+ __export(components_exports, {
479
+ Base: () => Base,
480
+ JsonLD: () => JsonLD,
481
+ Link: () => Link,
482
+ Meta: () => Meta,
483
+ Script: () => Script,
484
+ Title: () => Title
485
+ });
486
+ function read(v) {
487
+ return typeof v === "function" ? v() : v;
488
+ }
489
+ function Title(props) {
490
+ useHead(() => ({ title: read(props.children) }));
491
+ return null;
492
+ }
493
+ function Meta(props) {
494
+ useHead(() => ({ meta: [{ ...props, content: read(props.content) }] }));
495
+ return null;
496
+ }
497
+ function Link(props) {
498
+ useHead(() => {
499
+ const l = {};
500
+ for (const [k, v] of Object.entries(props)) l[k] = read(v);
501
+ return { link: [l] };
502
+ });
503
+ return null;
504
+ }
505
+ function Script(props) {
506
+ useHead(() => {
507
+ const s = {};
508
+ for (const [k, v] of Object.entries(props)) s[k] = read(v);
509
+ return { script: [s] };
510
+ });
511
+ return null;
512
+ }
513
+ function Base(props) {
514
+ useHead({ base: props.href });
515
+ return null;
516
+ }
517
+ function JsonLD(props) {
518
+ useHead(() => ({ jsonLd: read(props.data) }));
519
+ return null;
520
+ }
521
+
522
+ // src/sitemap.ts
523
+ function esc(s) {
524
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
525
+ }
526
+ function isoDate(d) {
527
+ return d instanceof Date ? d.toISOString() : d;
528
+ }
529
+ function renderEntry(e) {
530
+ let s = " <url>\n";
531
+ s += ` <loc>${esc(e.loc)}</loc>
532
+ `;
533
+ if (e.lastmod != null) s += ` <lastmod>${esc(isoDate(e.lastmod))}</lastmod>
534
+ `;
535
+ if (e.changefreq) s += ` <changefreq>${e.changefreq}</changefreq>
536
+ `;
537
+ if (e.priority != null) s += ` <priority>${e.priority.toFixed(1)}</priority>
538
+ `;
539
+ for (const a of e.alternates ?? []) s += ` <xhtml:link rel="alternate" hreflang="${esc(a.hreflang)}" href="${esc(a.href)}"/>
540
+ `;
541
+ for (const img of e.images ?? []) {
542
+ s += ` <image:image>
543
+ <image:loc>${esc(img.loc)}</image:loc>
544
+ `;
545
+ if (img.title) s += ` <image:title>${esc(img.title)}</image:title>
546
+ `;
547
+ if (img.caption) s += ` <image:caption>${esc(img.caption)}</image:caption>
548
+ `;
549
+ s += ` </image:image>
550
+ `;
551
+ }
552
+ for (const v of e.videos ?? []) {
553
+ s += ` <video:video>
554
+ <video:thumbnail_loc>${esc(v.thumbnailLoc)}</video:thumbnail_loc>
555
+ `;
556
+ s += ` <video:title>${esc(v.title)}</video:title>
557
+ <video:description>${esc(v.description)}</video:description>
558
+ `;
559
+ if (v.contentLoc) s += ` <video:content_loc>${esc(v.contentLoc)}</video:content_loc>
560
+ `;
561
+ if (v.playerLoc) s += ` <video:player_loc>${esc(v.playerLoc)}</video:player_loc>
562
+ `;
563
+ s += ` </video:video>
564
+ `;
565
+ }
566
+ s += " </url>\n";
567
+ return s;
568
+ }
569
+ function generateSitemap(entries) {
570
+ const ns = 'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"';
571
+ return `<?xml version="1.0" encoding="UTF-8"?>
572
+ <urlset ${ns}>
573
+ ${entries.map(renderEntry).join("")}</urlset>
574
+ `;
575
+ }
576
+ function chunkSitemap(entries, limit = 5e4) {
577
+ const out = [];
578
+ for (let i = 0; i < entries.length; i += limit) out.push(entries.slice(i, i + limit));
579
+ return out;
580
+ }
581
+ function generateSitemapIndex(sitemaps) {
582
+ let s = '<?xml version="1.0" encoding="UTF-8"?>\n<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
583
+ for (const sm of sitemaps) {
584
+ s += ` <sitemap>
585
+ <loc>${esc(sm.loc)}</loc>
586
+ `;
587
+ if (sm.lastmod != null) s += ` <lastmod>${esc(isoDate(sm.lastmod))}</lastmod>
588
+ `;
589
+ s += " </sitemap>\n";
590
+ }
591
+ return s + "</sitemapindex>\n";
592
+ }
593
+ function generateRobots(opts = {}) {
594
+ if (opts.production === false) {
595
+ return "User-agent: *\nDisallow: /\n";
596
+ }
597
+ const lines = [];
598
+ const rules = opts.rules ?? [{ userAgent: "*", allow: "/" }];
599
+ for (const r of rules) {
600
+ for (const ua of [].concat(r.userAgent)) lines.push(`User-agent: ${ua}`);
601
+ for (const a of [].concat(r.allow ?? [])) lines.push(`Allow: ${a}`);
602
+ for (const d of [].concat(r.disallow ?? [])) lines.push(`Disallow: ${d}`);
603
+ if (r.crawlDelay != null) lines.push(`Crawl-delay: ${r.crawlDelay}`);
604
+ lines.push("");
605
+ }
606
+ if (opts.host) lines.push(`Host: ${opts.host}`);
607
+ for (const sm of opts.sitemaps ?? []) lines.push(`Sitemap: ${sm}`);
608
+ return lines.join("\n").replace(/\n+$/, "\n");
609
+ }
610
+ export {
611
+ Base,
612
+ JsonLD,
613
+ KEY_ATTR,
614
+ Link,
615
+ MANAGED_ATTR,
616
+ Meta,
617
+ Script,
618
+ Title,
619
+ chunkSitemap,
620
+ components_exports as components,
621
+ createHead,
622
+ encodeHeadMarker,
623
+ extractHeadMarker,
624
+ generateRobots,
625
+ generateSitemap,
626
+ generateSitemapIndex,
627
+ getActiveHead,
628
+ jsonld,
629
+ mountHead,
630
+ renderHead,
631
+ renderHtmlAttrs,
632
+ resolveHead,
633
+ runWithHead,
634
+ seo,
635
+ setActiveHead,
636
+ stripHeadMarker,
637
+ useHead
638
+ };