@moku-labs/web 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +38 -0
- package/dist/bin/moku.cjs +809 -0
- package/dist/bin/moku.d.cts +1 -0
- package/dist/bin/moku.d.mts +1 -0
- package/dist/bin/moku.mjs +809 -0
- package/dist/factory-BBVQO5ZG.d.mts +90 -0
- package/dist/factory-CixCpR9C.cjs +1710 -0
- package/dist/factory-D0m7Xil2.d.cts +90 -0
- package/dist/factory-DwpBwjDk.mjs +1602 -0
- package/dist/index-CWdZdegx.d.mts +349 -0
- package/dist/index.cjs +46 -0
- package/dist/index.d.cts +135 -0
- package/dist/index.d.mts +135 -0
- package/dist/index.mjs +36 -0
- package/dist/plugins/head/build.cjs +35 -0
- package/dist/plugins/head/build.d.cts +17 -0
- package/dist/plugins/head/build.d.mts +17 -0
- package/dist/plugins/head/build.mjs +27 -0
- package/dist/plugins/spa/index.cjs +26 -0
- package/dist/plugins/spa/index.d.cts +30 -0
- package/dist/plugins/spa/index.d.mts +30 -0
- package/dist/plugins/spa/index.mjs +24 -0
- package/dist/primitives-BBo4wxUL.d.cts +69 -0
- package/dist/primitives-BYUp6kae.cjs +100 -0
- package/dist/primitives-gO5i1tD8.mjs +58 -0
- package/dist/primitives-kuZFxqV7.d.mts +69 -0
- package/dist/project-BTNUWbGQ.mjs +1020 -0
- package/dist/project-C1vtMxE8.cjs +1081 -0
- package/dist/route-builder-Lv6HUVvP.d.cts +349 -0
- package/dist/test.cjs +82 -0
- package/dist/test.d.cts +61 -0
- package/dist/test.d.mts +61 -0
- package/dist/test.mjs +79 -0
- package/package.json +100 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { c as route, d as coreConfig, f as createCore, l as site, o as head, s as router, t as createComponent, u as i18n } from "./factory-DwpBwjDk.mjs";
|
|
2
|
+
import { n as build, r as content, t as project } from "./project-BTNUWbGQ.mjs";
|
|
3
|
+
import { a as meta, i as jsonLd, n as feedLink, o as og, r as hreflang, s as twitter, t as canonical } from "./primitives-gO5i1tD8.mjs";
|
|
4
|
+
import { spa } from "./plugins/spa/index.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/index.ts
|
|
7
|
+
/** @file Framework entry — Layer-2 createApp wrapper + barrel re-exports. */
|
|
8
|
+
const { createApp: kernelCreateApp } = createCore(coreConfig, { plugins: [
|
|
9
|
+
site,
|
|
10
|
+
i18n,
|
|
11
|
+
content,
|
|
12
|
+
router,
|
|
13
|
+
head,
|
|
14
|
+
build,
|
|
15
|
+
spa
|
|
16
|
+
] });
|
|
17
|
+
/**
|
|
18
|
+
* Layer-2 createApp wrapper — generic-preserving signature.
|
|
19
|
+
*
|
|
20
|
+
* Projects the consumer's flat config into pluginConfigs before delegating to
|
|
21
|
+
* the kernel-bound createApp. The Routes generic flows through to
|
|
22
|
+
* `app.router.routes` so callers get typed access to their route names.
|
|
23
|
+
*
|
|
24
|
+
* @param input - Consumer-facing flat web-app config.
|
|
25
|
+
* @returns The assembled app with typed router routes.
|
|
26
|
+
*/
|
|
27
|
+
function createApp(input) {
|
|
28
|
+
const projected = project(input);
|
|
29
|
+
return kernelCreateApp({
|
|
30
|
+
...projected.config === void 0 ? {} : { config: projected.config },
|
|
31
|
+
pluginConfigs: projected.pluginConfigs
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { canonical, createApp, createComponent, feedLink, hreflang, jsonLd, meta, og, route, twitter };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_primitives = require('../../primitives-BYUp6kae.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/head/build.ts
|
|
5
|
+
/** @file Sub-path /build entry — pure build-time helpers (no plugin state access). */
|
|
6
|
+
/**
|
|
7
|
+
* Build a list of head elements for an article page from its frontmatter.
|
|
8
|
+
* Pure function — safe to call at build time without a plugin context.
|
|
9
|
+
*
|
|
10
|
+
* Always emits `<link rel=canonical>` and `<meta property=og:type content=article>`.
|
|
11
|
+
* Adds `og:article:*` meta tags for any provided frontmatter fields.
|
|
12
|
+
*
|
|
13
|
+
* @param meta - Article frontmatter (publishedTime, modifiedTime, author, section, tags).
|
|
14
|
+
* @param canonicalUrl - The fully-qualified canonical URL for the article.
|
|
15
|
+
* @returns Ordered array of HeadElements ready to feed into `head.render()`.
|
|
16
|
+
*/
|
|
17
|
+
const buildArticleHead = (meta, canonicalUrl) => {
|
|
18
|
+
const elements = [require_primitives.canonical(canonicalUrl), require_primitives.og("type", "article")];
|
|
19
|
+
if (meta.publishedTime) elements.push(require_primitives.og("article:published_time", meta.publishedTime));
|
|
20
|
+
if (meta.modifiedTime) elements.push(require_primitives.og("article:modified_time", meta.modifiedTime));
|
|
21
|
+
if (meta.author) elements.push(require_primitives.og("article:author", meta.author));
|
|
22
|
+
if (meta.section) elements.push(require_primitives.og("article:section", meta.section));
|
|
23
|
+
if (meta.tags) for (const tag of meta.tags) elements.push(require_primitives.og("article:tag", tag));
|
|
24
|
+
return elements;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
exports.buildArticleHead = buildArticleHead;
|
|
29
|
+
exports.canonical = require_primitives.canonical;
|
|
30
|
+
exports.feedLink = require_primitives.feedLink;
|
|
31
|
+
exports.hreflang = require_primitives.hreflang;
|
|
32
|
+
exports.jsonLd = require_primitives.jsonLd;
|
|
33
|
+
exports.meta = require_primitives.meta;
|
|
34
|
+
exports.og = require_primitives.og;
|
|
35
|
+
exports.twitter = require_primitives.twitter;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { a as meta, c as ArticleMeta, i as jsonLd, n as feedLink, o as og, r as hreflang, s as twitter, t as canonical, u as HeadElement } from "../../primitives-BBo4wxUL.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/head/build.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build a list of head elements for an article page from its frontmatter.
|
|
6
|
+
* Pure function — safe to call at build time without a plugin context.
|
|
7
|
+
*
|
|
8
|
+
* Always emits `<link rel=canonical>` and `<meta property=og:type content=article>`.
|
|
9
|
+
* Adds `og:article:*` meta tags for any provided frontmatter fields.
|
|
10
|
+
*
|
|
11
|
+
* @param meta - Article frontmatter (publishedTime, modifiedTime, author, section, tags).
|
|
12
|
+
* @param canonicalUrl - The fully-qualified canonical URL for the article.
|
|
13
|
+
* @returns Ordered array of HeadElements ready to feed into `head.render()`.
|
|
14
|
+
*/
|
|
15
|
+
declare const buildArticleHead: (meta: ArticleMeta, canonicalUrl: string) => HeadElement[];
|
|
16
|
+
//#endregion
|
|
17
|
+
export { type ArticleMeta, type HeadElement, buildArticleHead, canonical, feedLink, hreflang, jsonLd, meta, og, twitter };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { a as meta, c as ArticleMeta, i as jsonLd, n as feedLink, o as og, r as hreflang, s as twitter, t as canonical, u as HeadElement } from "../../primitives-kuZFxqV7.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/head/build.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build a list of head elements for an article page from its frontmatter.
|
|
6
|
+
* Pure function — safe to call at build time without a plugin context.
|
|
7
|
+
*
|
|
8
|
+
* Always emits `<link rel=canonical>` and `<meta property=og:type content=article>`.
|
|
9
|
+
* Adds `og:article:*` meta tags for any provided frontmatter fields.
|
|
10
|
+
*
|
|
11
|
+
* @param meta - Article frontmatter (publishedTime, modifiedTime, author, section, tags).
|
|
12
|
+
* @param canonicalUrl - The fully-qualified canonical URL for the article.
|
|
13
|
+
* @returns Ordered array of HeadElements ready to feed into `head.render()`.
|
|
14
|
+
*/
|
|
15
|
+
declare const buildArticleHead: (meta: ArticleMeta, canonicalUrl: string) => HeadElement[];
|
|
16
|
+
//#endregion
|
|
17
|
+
export { type ArticleMeta, type HeadElement, buildArticleHead, canonical, feedLink, hreflang, jsonLd, meta, og, twitter };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { a as meta, i as jsonLd, n as feedLink, o as og, r as hreflang, s as twitter, t as canonical } from "../../primitives-gO5i1tD8.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/head/build.ts
|
|
4
|
+
/** @file Sub-path /build entry — pure build-time helpers (no plugin state access). */
|
|
5
|
+
/**
|
|
6
|
+
* Build a list of head elements for an article page from its frontmatter.
|
|
7
|
+
* Pure function — safe to call at build time without a plugin context.
|
|
8
|
+
*
|
|
9
|
+
* Always emits `<link rel=canonical>` and `<meta property=og:type content=article>`.
|
|
10
|
+
* Adds `og:article:*` meta tags for any provided frontmatter fields.
|
|
11
|
+
*
|
|
12
|
+
* @param meta - Article frontmatter (publishedTime, modifiedTime, author, section, tags).
|
|
13
|
+
* @param canonicalUrl - The fully-qualified canonical URL for the article.
|
|
14
|
+
* @returns Ordered array of HeadElements ready to feed into `head.render()`.
|
|
15
|
+
*/
|
|
16
|
+
const buildArticleHead = (meta, canonicalUrl) => {
|
|
17
|
+
const elements = [canonical(canonicalUrl), og("type", "article")];
|
|
18
|
+
if (meta.publishedTime) elements.push(og("article:published_time", meta.publishedTime));
|
|
19
|
+
if (meta.modifiedTime) elements.push(og("article:modified_time", meta.modifiedTime));
|
|
20
|
+
if (meta.author) elements.push(og("article:author", meta.author));
|
|
21
|
+
if (meta.section) elements.push(og("article:section", meta.section));
|
|
22
|
+
if (meta.tags) for (const tag of meta.tags) elements.push(og("article:tag", tag));
|
|
23
|
+
return elements;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { buildArticleHead, canonical, feedLink, hreflang, jsonLd, meta, og, twitter };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_factory = require('../../factory-CixCpR9C.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/spa/index.ts
|
|
5
|
+
/** @file spa plugin: Very Complex tier — router + head + progress + components sub-modules. */
|
|
6
|
+
const defaultConfig = {
|
|
7
|
+
config: {
|
|
8
|
+
viewTransitions: false,
|
|
9
|
+
progressBar: true
|
|
10
|
+
},
|
|
11
|
+
components: []
|
|
12
|
+
};
|
|
13
|
+
const spa = require_factory.createPlugin("spa", {
|
|
14
|
+
depends: [require_factory.router, require_factory.head],
|
|
15
|
+
config: defaultConfig,
|
|
16
|
+
events: require_factory.registerSpaEvents,
|
|
17
|
+
createState: require_factory.createSpaState,
|
|
18
|
+
api: require_factory.createSpaApi,
|
|
19
|
+
onStart: async (ctx) => {
|
|
20
|
+
if (typeof window !== "undefined") await require_factory.createClientRuntime(ctx).start();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
exports.createComponent = require_factory.createComponent;
|
|
26
|
+
exports.spa = spa;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { a as SpaConfig, i as SpaApi, o as SpaState, t as createComponent } from "../../factory-D0m7Xil2.cjs";
|
|
2
|
+
import * as _moku_labs_core0 from "@moku-labs/core";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/spa/index.d.ts
|
|
5
|
+
declare const spa: _moku_labs_core0.PluginInstance<"spa", SpaConfig, SpaState, SpaApi, {
|
|
6
|
+
'component:create': {
|
|
7
|
+
name: string;
|
|
8
|
+
element: Element;
|
|
9
|
+
};
|
|
10
|
+
'component:mount': {
|
|
11
|
+
name: string;
|
|
12
|
+
element: Element;
|
|
13
|
+
};
|
|
14
|
+
'component:unmount': {
|
|
15
|
+
name: string;
|
|
16
|
+
reason: "navigation" | "destroy";
|
|
17
|
+
};
|
|
18
|
+
'component:destroy': {
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
'nav:start': {
|
|
22
|
+
url: string;
|
|
23
|
+
fromUrl: string;
|
|
24
|
+
};
|
|
25
|
+
'nav:end': {
|
|
26
|
+
url: string;
|
|
27
|
+
};
|
|
28
|
+
}> & Record<never, never>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createComponent, spa };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { a as SpaConfig, i as SpaApi, o as SpaState, t as createComponent } from "../../factory-BBVQO5ZG.mjs";
|
|
2
|
+
import * as _moku_labs_core0 from "@moku-labs/core";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/spa/index.d.ts
|
|
5
|
+
declare const spa: _moku_labs_core0.PluginInstance<"spa", SpaConfig, SpaState, SpaApi, {
|
|
6
|
+
'component:create': {
|
|
7
|
+
name: string;
|
|
8
|
+
element: Element;
|
|
9
|
+
};
|
|
10
|
+
'component:mount': {
|
|
11
|
+
name: string;
|
|
12
|
+
element: Element;
|
|
13
|
+
};
|
|
14
|
+
'component:unmount': {
|
|
15
|
+
name: string;
|
|
16
|
+
reason: "navigation" | "destroy";
|
|
17
|
+
};
|
|
18
|
+
'component:destroy': {
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
'nav:start': {
|
|
22
|
+
url: string;
|
|
23
|
+
fromUrl: string;
|
|
24
|
+
};
|
|
25
|
+
'nav:end': {
|
|
26
|
+
url: string;
|
|
27
|
+
};
|
|
28
|
+
}> & Record<never, never>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createComponent, spa };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { a as createSpaApi, i as createClientRuntime, n as createSpaState, o as head, p as createPlugin, r as registerSpaEvents, s as router, t as createComponent } from "../../factory-DwpBwjDk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/spa/index.ts
|
|
4
|
+
/** @file spa plugin: Very Complex tier — router + head + progress + components sub-modules. */
|
|
5
|
+
const defaultConfig = {
|
|
6
|
+
config: {
|
|
7
|
+
viewTransitions: false,
|
|
8
|
+
progressBar: true
|
|
9
|
+
},
|
|
10
|
+
components: []
|
|
11
|
+
};
|
|
12
|
+
const spa = createPlugin("spa", {
|
|
13
|
+
depends: [router, head],
|
|
14
|
+
config: defaultConfig,
|
|
15
|
+
events: registerSpaEvents,
|
|
16
|
+
createState: createSpaState,
|
|
17
|
+
api: createSpaApi,
|
|
18
|
+
onStart: async (ctx) => {
|
|
19
|
+
if (typeof window !== "undefined") await createClientRuntime(ctx).start();
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { createComponent, spa };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region src/plugins/head/types.d.ts
|
|
2
|
+
/** @file head plugin types — HeadElement, HeadConfig, ArticleMeta, OGImageConfig. */
|
|
3
|
+
type HeadElement = {
|
|
4
|
+
tag: 'meta' | 'link' | 'script' | 'title';
|
|
5
|
+
attrs: Record<string, string>;
|
|
6
|
+
content?: string;
|
|
7
|
+
};
|
|
8
|
+
type HeadConfig = {
|
|
9
|
+
title?: string;
|
|
10
|
+
elements?: HeadElement[];
|
|
11
|
+
};
|
|
12
|
+
type ArticleMeta = {
|
|
13
|
+
publishedTime?: string;
|
|
14
|
+
modifiedTime?: string;
|
|
15
|
+
author?: string;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
section?: string;
|
|
18
|
+
};
|
|
19
|
+
type OGFontConfig = {
|
|
20
|
+
subset: string;
|
|
21
|
+
weights: number[];
|
|
22
|
+
};
|
|
23
|
+
type OGImageConfig = {
|
|
24
|
+
template?: unknown;
|
|
25
|
+
fontDir?: string;
|
|
26
|
+
fontName?: string;
|
|
27
|
+
fonts?: OGFontConfig[];
|
|
28
|
+
};
|
|
29
|
+
type HeadPluginConfig = {
|
|
30
|
+
ogImage?: OGImageConfig;
|
|
31
|
+
titleSeparator?: string;
|
|
32
|
+
autoCanonical?: boolean;
|
|
33
|
+
};
|
|
34
|
+
type HeadState = {
|
|
35
|
+
config: Readonly<HeadPluginConfig>;
|
|
36
|
+
ogImageDefaults: Readonly<OGImageConfig> | null;
|
|
37
|
+
};
|
|
38
|
+
type RenderContext = {
|
|
39
|
+
url: string;
|
|
40
|
+
locale: string;
|
|
41
|
+
};
|
|
42
|
+
type HeadApi = {
|
|
43
|
+
render(config: HeadConfig, ctx: RenderContext): string;
|
|
44
|
+
primitives: {
|
|
45
|
+
meta(name: string, content: string): HeadElement;
|
|
46
|
+
og(property: string, content: string): HeadElement;
|
|
47
|
+
jsonLd(data: unknown): HeadElement;
|
|
48
|
+
canonical(url: string): HeadElement;
|
|
49
|
+
hreflang(locale: string, url: string): HeadElement;
|
|
50
|
+
twitter(name: string, content: string): HeadElement;
|
|
51
|
+
feedLink(title: string, url: string, type?: 'rss' | 'atom'): HeadElement;
|
|
52
|
+
};
|
|
53
|
+
buildArticleHead(meta: ArticleMeta, canonicalUrl: string): HeadElement[];
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/plugins/head/primitives.d.ts
|
|
57
|
+
declare const meta: (name: string, content: string) => HeadElement;
|
|
58
|
+
declare const og: (property: string, content: string) => HeadElement;
|
|
59
|
+
/**
|
|
60
|
+
* JSON-LD with unicode-escape XSS protection. `JSON.stringify` alone is exploitable via `</script>` injection.
|
|
61
|
+
* Escape sequence prevents script-context breakout. NEVER add an `unsafe: true` opt-out — this is non-negotiable.
|
|
62
|
+
*/
|
|
63
|
+
declare const jsonLd: (data: unknown) => HeadElement;
|
|
64
|
+
declare const canonical: (url: string) => HeadElement;
|
|
65
|
+
declare const hreflang: (locale: string, url: string) => HeadElement;
|
|
66
|
+
declare const twitter: (name: string, content: string) => HeadElement;
|
|
67
|
+
declare const feedLink: (title: string, url: string, type?: "rss" | "atom") => HeadElement;
|
|
68
|
+
//#endregion
|
|
69
|
+
export { meta as a, ArticleMeta as c, HeadPluginConfig as d, HeadState as f, jsonLd as i, HeadApi as l, feedLink as n, og as o, OGImageConfig as p, hreflang as r, twitter as s, canonical as t, HeadElement as u };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/plugins/head/primitives.ts
|
|
3
|
+
const meta = (name, content) => ({
|
|
4
|
+
tag: "meta",
|
|
5
|
+
attrs: {
|
|
6
|
+
name,
|
|
7
|
+
content
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
const og = (property, content) => ({
|
|
11
|
+
tag: "meta",
|
|
12
|
+
attrs: {
|
|
13
|
+
property: `og:${property}`,
|
|
14
|
+
content
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* JSON-LD with unicode-escape XSS protection. `JSON.stringify` alone is exploitable via `<\/script>` injection.
|
|
19
|
+
* Escape sequence prevents script-context breakout. NEVER add an `unsafe: true` opt-out — this is non-negotiable.
|
|
20
|
+
*/
|
|
21
|
+
const jsonLd = (data) => ({
|
|
22
|
+
tag: "script",
|
|
23
|
+
attrs: { type: "application/ld+json" },
|
|
24
|
+
content: JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026")
|
|
25
|
+
});
|
|
26
|
+
const canonical = (url) => ({
|
|
27
|
+
tag: "link",
|
|
28
|
+
attrs: {
|
|
29
|
+
rel: "canonical",
|
|
30
|
+
href: url
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const hreflang = (locale, url) => ({
|
|
34
|
+
tag: "link",
|
|
35
|
+
attrs: {
|
|
36
|
+
rel: "alternate",
|
|
37
|
+
hreflang: locale,
|
|
38
|
+
href: url
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const twitter = (name, content) => ({
|
|
42
|
+
tag: "meta",
|
|
43
|
+
attrs: {
|
|
44
|
+
name: `twitter:${name}`,
|
|
45
|
+
content
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const feedLink = (title, url, type = "rss") => ({
|
|
49
|
+
tag: "link",
|
|
50
|
+
attrs: {
|
|
51
|
+
rel: "alternate",
|
|
52
|
+
type: type === "rss" ? "application/rss+xml" : "application/atom+xml",
|
|
53
|
+
title,
|
|
54
|
+
href: url
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
Object.defineProperty(exports, 'canonical', {
|
|
60
|
+
enumerable: true,
|
|
61
|
+
get: function () {
|
|
62
|
+
return canonical;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
Object.defineProperty(exports, 'feedLink', {
|
|
66
|
+
enumerable: true,
|
|
67
|
+
get: function () {
|
|
68
|
+
return feedLink;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
Object.defineProperty(exports, 'hreflang', {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
get: function () {
|
|
74
|
+
return hreflang;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
Object.defineProperty(exports, 'jsonLd', {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
get: function () {
|
|
80
|
+
return jsonLd;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(exports, 'meta', {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
get: function () {
|
|
86
|
+
return meta;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
Object.defineProperty(exports, 'og', {
|
|
90
|
+
enumerable: true,
|
|
91
|
+
get: function () {
|
|
92
|
+
return og;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
Object.defineProperty(exports, 'twitter', {
|
|
96
|
+
enumerable: true,
|
|
97
|
+
get: function () {
|
|
98
|
+
return twitter;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/plugins/head/primitives.ts
|
|
2
|
+
const meta = (name, content) => ({
|
|
3
|
+
tag: "meta",
|
|
4
|
+
attrs: {
|
|
5
|
+
name,
|
|
6
|
+
content
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
const og = (property, content) => ({
|
|
10
|
+
tag: "meta",
|
|
11
|
+
attrs: {
|
|
12
|
+
property: `og:${property}`,
|
|
13
|
+
content
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* JSON-LD with unicode-escape XSS protection. `JSON.stringify` alone is exploitable via `<\/script>` injection.
|
|
18
|
+
* Escape sequence prevents script-context breakout. NEVER add an `unsafe: true` opt-out — this is non-negotiable.
|
|
19
|
+
*/
|
|
20
|
+
const jsonLd = (data) => ({
|
|
21
|
+
tag: "script",
|
|
22
|
+
attrs: { type: "application/ld+json" },
|
|
23
|
+
content: JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026")
|
|
24
|
+
});
|
|
25
|
+
const canonical = (url) => ({
|
|
26
|
+
tag: "link",
|
|
27
|
+
attrs: {
|
|
28
|
+
rel: "canonical",
|
|
29
|
+
href: url
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const hreflang = (locale, url) => ({
|
|
33
|
+
tag: "link",
|
|
34
|
+
attrs: {
|
|
35
|
+
rel: "alternate",
|
|
36
|
+
hreflang: locale,
|
|
37
|
+
href: url
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const twitter = (name, content) => ({
|
|
41
|
+
tag: "meta",
|
|
42
|
+
attrs: {
|
|
43
|
+
name: `twitter:${name}`,
|
|
44
|
+
content
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const feedLink = (title, url, type = "rss") => ({
|
|
48
|
+
tag: "link",
|
|
49
|
+
attrs: {
|
|
50
|
+
rel: "alternate",
|
|
51
|
+
type: type === "rss" ? "application/rss+xml" : "application/atom+xml",
|
|
52
|
+
title,
|
|
53
|
+
href: url
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { meta as a, jsonLd as i, feedLink as n, og as o, hreflang as r, twitter as s, canonical as t };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region src/plugins/head/types.d.ts
|
|
2
|
+
/** @file head plugin types — HeadElement, HeadConfig, ArticleMeta, OGImageConfig. */
|
|
3
|
+
type HeadElement = {
|
|
4
|
+
tag: 'meta' | 'link' | 'script' | 'title';
|
|
5
|
+
attrs: Record<string, string>;
|
|
6
|
+
content?: string;
|
|
7
|
+
};
|
|
8
|
+
type HeadConfig = {
|
|
9
|
+
title?: string;
|
|
10
|
+
elements?: HeadElement[];
|
|
11
|
+
};
|
|
12
|
+
type ArticleMeta = {
|
|
13
|
+
publishedTime?: string;
|
|
14
|
+
modifiedTime?: string;
|
|
15
|
+
author?: string;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
section?: string;
|
|
18
|
+
};
|
|
19
|
+
type OGFontConfig = {
|
|
20
|
+
subset: string;
|
|
21
|
+
weights: number[];
|
|
22
|
+
};
|
|
23
|
+
type OGImageConfig = {
|
|
24
|
+
template?: unknown;
|
|
25
|
+
fontDir?: string;
|
|
26
|
+
fontName?: string;
|
|
27
|
+
fonts?: OGFontConfig[];
|
|
28
|
+
};
|
|
29
|
+
type HeadPluginConfig = {
|
|
30
|
+
ogImage?: OGImageConfig;
|
|
31
|
+
titleSeparator?: string;
|
|
32
|
+
autoCanonical?: boolean;
|
|
33
|
+
};
|
|
34
|
+
type HeadState = {
|
|
35
|
+
config: Readonly<HeadPluginConfig>;
|
|
36
|
+
ogImageDefaults: Readonly<OGImageConfig> | null;
|
|
37
|
+
};
|
|
38
|
+
type RenderContext = {
|
|
39
|
+
url: string;
|
|
40
|
+
locale: string;
|
|
41
|
+
};
|
|
42
|
+
type HeadApi = {
|
|
43
|
+
render(config: HeadConfig, ctx: RenderContext): string;
|
|
44
|
+
primitives: {
|
|
45
|
+
meta(name: string, content: string): HeadElement;
|
|
46
|
+
og(property: string, content: string): HeadElement;
|
|
47
|
+
jsonLd(data: unknown): HeadElement;
|
|
48
|
+
canonical(url: string): HeadElement;
|
|
49
|
+
hreflang(locale: string, url: string): HeadElement;
|
|
50
|
+
twitter(name: string, content: string): HeadElement;
|
|
51
|
+
feedLink(title: string, url: string, type?: 'rss' | 'atom'): HeadElement;
|
|
52
|
+
};
|
|
53
|
+
buildArticleHead(meta: ArticleMeta, canonicalUrl: string): HeadElement[];
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/plugins/head/primitives.d.ts
|
|
57
|
+
declare const meta: (name: string, content: string) => HeadElement;
|
|
58
|
+
declare const og: (property: string, content: string) => HeadElement;
|
|
59
|
+
/**
|
|
60
|
+
* JSON-LD with unicode-escape XSS protection. `JSON.stringify` alone is exploitable via `</script>` injection.
|
|
61
|
+
* Escape sequence prevents script-context breakout. NEVER add an `unsafe: true` opt-out — this is non-negotiable.
|
|
62
|
+
*/
|
|
63
|
+
declare const jsonLd: (data: unknown) => HeadElement;
|
|
64
|
+
declare const canonical: (url: string) => HeadElement;
|
|
65
|
+
declare const hreflang: (locale: string, url: string) => HeadElement;
|
|
66
|
+
declare const twitter: (name: string, content: string) => HeadElement;
|
|
67
|
+
declare const feedLink: (title: string, url: string, type?: "rss" | "atom") => HeadElement;
|
|
68
|
+
//#endregion
|
|
69
|
+
export { meta as a, ArticleMeta as c, HeadPluginConfig as d, HeadState as f, jsonLd as i, HeadApi as l, feedLink as n, og as o, OGImageConfig as p, hreflang as r, twitter as s, canonical as t, HeadElement as u };
|