@ox-content/vite-plugin 2.81.0 → 2.82.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.
Files changed (68) hide show
  1. package/dist/incremental-dom.cjs +3 -2
  2. package/dist/incremental-dom.cjs.map +1 -1
  3. package/dist/incremental-dom.d.cts.map +1 -1
  4. package/dist/incremental-dom.d.mts.map +1 -1
  5. package/dist/incremental-dom.mjs +2 -1
  6. package/dist/incremental-dom.mjs.map +1 -1
  7. package/dist/index.cjs +1486 -99
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +8 -13
  10. package/dist/index.d.cts.map +1 -1
  11. package/dist/index.d.mts +8 -13
  12. package/dist/index.d.mts.map +1 -1
  13. package/dist/index.mjs +1429 -69
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/interop.cjs.map +1 -1
  16. package/dist/interop.mjs.map +1 -1
  17. package/dist/tabs.cjs +3 -4
  18. package/dist/tabs.cjs.map +1 -1
  19. package/dist/tabs.mjs +99 -2
  20. package/dist/tabs.mjs.map +1 -0
  21. package/dist/vitepress-cli.cjs +5 -4
  22. package/dist/vitepress-cli.cjs.map +1 -1
  23. package/dist/vitepress-cli.d.cts +1 -1
  24. package/dist/vitepress-cli.d.mts +1 -1
  25. package/dist/vitepress-cli.mjs +4 -2
  26. package/dist/vitepress-cli.mjs.map +1 -1
  27. package/dist/vitepress.cjs +106 -2
  28. package/dist/vitepress.cjs.map +1 -1
  29. package/dist/vitepress.mjs +32 -2
  30. package/dist/vitepress.mjs.map +1 -1
  31. package/package.json +19 -19
  32. package/dist/chunk.cjs +0 -57
  33. package/dist/github.cjs +0 -690
  34. package/dist/github.cjs.map +0 -1
  35. package/dist/github.mjs +0 -625
  36. package/dist/github.mjs.map +0 -1
  37. package/dist/github2.mjs +0 -2
  38. package/dist/media.cjs +0 -310
  39. package/dist/media.cjs.map +0 -1
  40. package/dist/media.mjs +0 -302
  41. package/dist/media.mjs.map +0 -1
  42. package/dist/media2.mjs +0 -2
  43. package/dist/mermaid.cjs +0 -114
  44. package/dist/mermaid.cjs.map +0 -1
  45. package/dist/mermaid.mjs +0 -2
  46. package/dist/mermaid2.mjs +0 -92
  47. package/dist/mermaid2.mjs.map +0 -1
  48. package/dist/napi.cjs +0 -45
  49. package/dist/napi.cjs.map +0 -1
  50. package/dist/napi.mjs +0 -34
  51. package/dist/napi.mjs.map +0 -1
  52. package/dist/ogp.cjs +0 -341
  53. package/dist/ogp.cjs.map +0 -1
  54. package/dist/ogp.mjs +0 -2
  55. package/dist/ogp2.mjs +0 -302
  56. package/dist/ogp2.mjs.map +0 -1
  57. package/dist/pm.cjs +0 -45
  58. package/dist/pm.cjs.map +0 -1
  59. package/dist/pm.mjs +0 -2
  60. package/dist/pm2.mjs +0 -38
  61. package/dist/pm2.mjs.map +0 -1
  62. package/dist/tabs2.mjs +0 -56
  63. package/dist/tabs2.mjs.map +0 -1
  64. package/dist/youtube.cjs +0 -57
  65. package/dist/youtube.cjs.map +0 -1
  66. package/dist/youtube.mjs +0 -2
  67. package/dist/youtube2.mjs +0 -35
  68. package/dist/youtube2.mjs.map +0 -1
package/dist/napi.mjs DELETED
@@ -1,34 +0,0 @@
1
- import { createRequire } from "node:module";
2
- //#region src/napi.ts
3
- const requireNapi = createRequire(import.meta.url);
4
- function getDefaultExport(value) {
5
- if (!value || typeof value !== "object" || !("default" in value)) return;
6
- const defaultExport = value.default;
7
- return defaultExport && typeof defaultExport === "object" ? defaultExport : void 0;
8
- }
9
- function normalizeNapiModule(mod) {
10
- const defaultExport = getDefaultExport(mod);
11
- return defaultExport ? {
12
- ...defaultExport,
13
- ...mod
14
- } : mod;
15
- }
16
- async function importNapiModule() {
17
- return normalizeNapiModule(await import("@ox-content/napi"));
18
- }
19
- let syncNapiModule;
20
- function importNapiModuleSync() {
21
- if (syncNapiModule) return syncNapiModule;
22
- if (syncNapiModule === null) throw new Error("[ox-content] @ox-content/napi is required. Please ensure the NAPI module is built.");
23
- try {
24
- syncNapiModule = normalizeNapiModule(requireNapi("@ox-content/napi"));
25
- return syncNapiModule;
26
- } catch {
27
- syncNapiModule = null;
28
- throw new Error("[ox-content] @ox-content/napi is required. Please ensure the NAPI module is built.");
29
- }
30
- }
31
- //#endregion
32
- export { importNapiModuleSync as n, importNapiModule as t };
33
-
34
- //# sourceMappingURL=napi.mjs.map
package/dist/napi.mjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"napi.mjs","names":[],"sources":["../src/napi.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\ntype NapiModule = typeof import(\"@ox-content/napi\");\nconst requireNapi = createRequire(import.meta.url);\n\nfunction getDefaultExport(value: unknown): object | undefined {\n if (!value || typeof value !== \"object\" || !(\"default\" in value)) {\n return undefined;\n }\n\n const defaultExport = value.default;\n return defaultExport && typeof defaultExport === \"object\" ? defaultExport : undefined;\n}\n\nfunction normalizeNapiModule(mod: NapiModule): NapiModule {\n const defaultExport = getDefaultExport(mod);\n return defaultExport\n ? ({\n ...defaultExport,\n ...mod,\n } as NapiModule)\n : mod;\n}\n\nexport async function importNapiModule(): Promise<NapiModule> {\n return normalizeNapiModule((await import(\"@ox-content/napi\")) as NapiModule);\n}\n\nlet syncNapiModule: NapiModule | null | undefined;\n\nexport function importNapiModuleSync(): NapiModule {\n if (syncNapiModule) {\n return syncNapiModule;\n }\n\n if (syncNapiModule === null) {\n throw new Error(\n \"[ox-content] @ox-content/napi is required. Please ensure the NAPI module is built.\",\n );\n }\n\n try {\n const mod = requireNapi(\"@ox-content/napi\") as NapiModule;\n syncNapiModule = normalizeNapiModule(mod);\n return syncNapiModule;\n } catch {\n syncNapiModule = null;\n throw new Error(\n \"[ox-content] @ox-content/napi is required. Please ensure the NAPI module is built.\",\n );\n }\n}\n"],"mappings":";;AAGA,MAAM,cAAc,cAAc,OAAO,KAAK,IAAI;AAElD,SAAS,iBAAiB,OAAoC;CAC5D,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,EAAE,aAAa,QACxD;CAGF,MAAM,gBAAgB,MAAM;CAC5B,OAAO,iBAAiB,OAAO,kBAAkB,WAAW,gBAAgB,KAAA;;AAG9E,SAAS,oBAAoB,KAA6B;CACxD,MAAM,gBAAgB,iBAAiB,IAAI;CAC3C,OAAO,gBACF;EACC,GAAG;EACH,GAAG;EACJ,GACD;;AAGN,eAAsB,mBAAwC;CAC5D,OAAO,oBAAqB,MAAM,OAAO,oBAAmC;;AAG9E,IAAI;AAEJ,SAAgB,uBAAmC;CACjD,IAAI,gBACF,OAAO;CAGT,IAAI,mBAAmB,MACrB,MAAM,IAAI,MACR,qFACD;CAGH,IAAI;EAEF,iBAAiB,oBADL,YAAY,mBACgB,CAAC;EACzC,OAAO;SACD;EACN,iBAAiB;EACjB,MAAM,IAAI,MACR,qFACD"}
package/dist/ogp.cjs DELETED
@@ -1,341 +0,0 @@
1
- const require_chunk = require("./chunk.cjs");
2
- const require_interop = require("./interop.cjs");
3
- let unified = require("unified");
4
- let rehype_parse = require("rehype-parse");
5
- rehype_parse = require_chunk.__toESM(rehype_parse, 1);
6
- let rehype_stringify = require("rehype-stringify");
7
- rehype_stringify = require_chunk.__toESM(rehype_stringify, 1);
8
- //#region src/plugins/ogp.ts
9
- /**
10
- * OGP Card Plugin - Link card embedding
11
- *
12
- * Transforms <OgCard> components into static link preview cards
13
- * by fetching OGP metadata at build time.
14
- */
15
- var ogp_exports = /* @__PURE__ */ require_chunk.__exportAll({
16
- collectOgpUrls: () => collectOgpUrls,
17
- fetchOgpData: () => fetchOgpData,
18
- isSafeOgpUrl: () => isSafeOgpUrl,
19
- prefetchOgpData: () => prefetchOgpData,
20
- transformOgp: () => transformOgp
21
- });
22
- const rehypeParse = require_interop.interopDefault(rehype_parse.default);
23
- const rehypeStringify = require_interop.interopDefault(rehype_stringify.default);
24
- const defaultOptions = {
25
- timeout: 1e4,
26
- cache: true,
27
- cacheTTL: 36e5,
28
- userAgent: "ox-content-ogp-bot/1.0 (compatible; +https://github.com/ubugeeei-prod/ox-content)"
29
- };
30
- const ogpCache = /* @__PURE__ */ new Map();
31
- function isPrivateIPv4(hostname) {
32
- const parts = hostname.split(".").map(Number);
33
- if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return false;
34
- const [a, b] = parts;
35
- return a === 10 || a === 127 || a === 0 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 169 && b === 254;
36
- }
37
- function isSafeOgpUrl(value) {
38
- try {
39
- const url = new URL(value);
40
- const host = url.hostname.toLowerCase();
41
- const ipv6 = host.replace(/^\[|\]$/g, "");
42
- if (url.protocol !== "http:" && url.protocol !== "https:") return false;
43
- if (host === "localhost" || host.endsWith(".localhost")) return false;
44
- if (ipv6.includes(":") && (ipv6 === "::1" || ipv6.startsWith("fc") || ipv6.startsWith("fd") || ipv6.startsWith("fe80"))) return false;
45
- return !isPrivateIPv4(host);
46
- } catch {
47
- return false;
48
- }
49
- }
50
- /**
51
- * Get element attribute value.
52
- */
53
- function getAttribute(el, name) {
54
- const value = el.properties?.[name];
55
- if (typeof value === "string") return value;
56
- if (Array.isArray(value)) return value.join(" ");
57
- }
58
- /**
59
- * Extract domain from URL.
60
- */
61
- function extractDomain(url) {
62
- try {
63
- return new URL(url).hostname;
64
- } catch {
65
- return url;
66
- }
67
- }
68
- /**
69
- * Get favicon URL for a domain.
70
- */
71
- function getFaviconUrl(url) {
72
- try {
73
- return `https://www.google.com/s2/favicons?domain=${new URL(url).hostname}&sz=32`;
74
- } catch {
75
- return "";
76
- }
77
- }
78
- /**
79
- * Parse OGP metadata from HTML.
80
- */
81
- function parseOgpFromHtml(html, url) {
82
- const result = {
83
- url,
84
- title: ""
85
- };
86
- const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i);
87
- result.title = (html.match(/<meta[^>]*property=["']og:title["'][^>]*content=["']([^"']+)["']/i) || html.match(/<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:title["']/i))?.[1] || titleMatch?.[1] || extractDomain(url);
88
- const descMatch = html.match(/<meta[^>]*property=["']og:description["'][^>]*content=["']([^"']+)["']/i) || html.match(/<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:description["']/i) || html.match(/<meta[^>]*name=["']description["'][^>]*content=["']([^"']+)["']/i) || html.match(/<meta[^>]*content=["']([^"']+)["'][^>]*name=["']description["']/i);
89
- if (descMatch) result.description = descMatch[1];
90
- const imageMatch = html.match(/<meta[^>]*property=["']og:image["'][^>]*content=["']([^"']+)["']/i) || html.match(/<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:image["']/i);
91
- if (imageMatch) {
92
- let imageUrl = imageMatch[1];
93
- if (imageUrl.startsWith("/")) try {
94
- const urlObj = new URL(url);
95
- imageUrl = `${urlObj.protocol}//${urlObj.host}${imageUrl}`;
96
- } catch {}
97
- result.image = imageUrl;
98
- }
99
- const siteNameMatch = html.match(/<meta[^>]*property=["']og:site_name["'][^>]*content=["']([^"']+)["']/i) || html.match(/<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:site_name["']/i);
100
- if (siteNameMatch) result.siteName = siteNameMatch[1];
101
- result.favicon = getFaviconUrl(url);
102
- return result;
103
- }
104
- /**
105
- * Fetch OGP data for a URL.
106
- */
107
- async function fetchOgpData(url, options) {
108
- if (!isSafeOgpUrl(url)) return null;
109
- if (options.cache) {
110
- const cached = ogpCache.get(url);
111
- if (cached && Date.now() - cached.timestamp < options.cacheTTL) return cached.data;
112
- }
113
- try {
114
- const controller = new AbortController();
115
- const timeoutId = setTimeout(() => controller.abort(), options.timeout);
116
- const response = await fetch(url, {
117
- headers: {
118
- "User-Agent": options.userAgent,
119
- Accept: "text/html,application/xhtml+xml"
120
- },
121
- signal: controller.signal
122
- });
123
- clearTimeout(timeoutId);
124
- if (!response.ok) {
125
- console.warn(`Failed to fetch OGP for ${url}: ${response.status}`);
126
- return null;
127
- }
128
- const data = parseOgpFromHtml(await response.text(), url);
129
- if (options.cache) ogpCache.set(url, {
130
- data,
131
- timestamp: Date.now()
132
- });
133
- return data;
134
- } catch (error) {
135
- if (error instanceof Error && error.name === "AbortError") console.warn(`Timeout fetching OGP for ${url}`);
136
- else console.warn(`Error fetching OGP for ${url}:`, error);
137
- return null;
138
- }
139
- }
140
- /**
141
- * Create OGP card element.
142
- */
143
- function createOgpCard(data) {
144
- const children = [];
145
- const contentChildren = [];
146
- contentChildren.push({
147
- type: "element",
148
- tagName: "div",
149
- properties: { className: ["ox-ogp-title"] },
150
- children: [{
151
- type: "text",
152
- value: data.title
153
- }]
154
- });
155
- if (data.description) contentChildren.push({
156
- type: "element",
157
- tagName: "div",
158
- properties: { className: ["ox-ogp-description"] },
159
- children: [{
160
- type: "text",
161
- value: data.description
162
- }]
163
- });
164
- const metaChildren = [];
165
- if (data.favicon) metaChildren.push({
166
- type: "element",
167
- tagName: "img",
168
- properties: {
169
- className: ["ox-ogp-favicon"],
170
- src: data.favicon,
171
- alt: "",
172
- loading: "lazy"
173
- },
174
- children: []
175
- });
176
- metaChildren.push({
177
- type: "element",
178
- tagName: "span",
179
- properties: { className: ["ox-ogp-domain"] },
180
- children: [{
181
- type: "text",
182
- value: data.siteName || extractDomain(data.url)
183
- }]
184
- });
185
- contentChildren.push({
186
- type: "element",
187
- tagName: "div",
188
- properties: { className: ["ox-ogp-meta"] },
189
- children: metaChildren
190
- });
191
- children.push({
192
- type: "element",
193
- tagName: "div",
194
- properties: { className: ["ox-ogp-content"] },
195
- children: contentChildren
196
- });
197
- if (data.image) children.push({
198
- type: "element",
199
- tagName: "img",
200
- properties: {
201
- className: ["ox-ogp-image"],
202
- src: data.image,
203
- alt: "",
204
- loading: "lazy"
205
- },
206
- children: []
207
- });
208
- return {
209
- type: "element",
210
- tagName: "a",
211
- properties: {
212
- className: ["ox-ogp-card"],
213
- href: isSafeOgpUrl(data.url) ? data.url : "#",
214
- target: "_blank",
215
- rel: "noopener noreferrer"
216
- },
217
- children
218
- };
219
- }
220
- /**
221
- * Create fallback element when OGP data is unavailable.
222
- */
223
- function createFallbackCard(url) {
224
- return {
225
- type: "element",
226
- tagName: "a",
227
- properties: {
228
- className: ["ox-ogp-simple"],
229
- href: isSafeOgpUrl(url) ? url : "#",
230
- target: "_blank",
231
- rel: "noopener noreferrer"
232
- },
233
- children: [{
234
- type: "element",
235
- tagName: "svg",
236
- properties: {
237
- viewBox: "0 0 24 24",
238
- fill: "none",
239
- stroke: "currentColor",
240
- "stroke-width": "2"
241
- },
242
- children: [{
243
- type: "element",
244
- tagName: "path",
245
- properties: { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3" },
246
- children: []
247
- }]
248
- }, {
249
- type: "text",
250
- value: extractDomain(url)
251
- }]
252
- };
253
- }
254
- /**
255
- * Collect all OGP URLs from HTML for pre-fetching.
256
- */
257
- async function collectOgpUrls(html) {
258
- const urls = [];
259
- const urlPattern = /<ogcard[^>]*\s+url=["']([^"']+)["']/gi;
260
- let match;
261
- while ((match = urlPattern.exec(html)) !== null) if (isSafeOgpUrl(match[1])) urls.push(match[1]);
262
- return urls;
263
- }
264
- /**
265
- * Pre-fetch all OGP data.
266
- */
267
- async function prefetchOgpData(urls, options) {
268
- const mergedOptions = {
269
- ...defaultOptions,
270
- ...options
271
- };
272
- const results = /* @__PURE__ */ new Map();
273
- await Promise.all(urls.map(async (url) => {
274
- const data = await fetchOgpData(url, mergedOptions);
275
- results.set(url, data);
276
- }));
277
- return results;
278
- }
279
- /**
280
- * Rehype plugin to transform OgCard components.
281
- */
282
- function rehypeOgp(ogpDataMap) {
283
- return (tree) => {
284
- const visit = (node) => {
285
- if ("children" in node) for (let i = 0; i < node.children.length; i++) {
286
- const child = node.children[i];
287
- if (child.type === "element") if (child.tagName.toLowerCase() === "ogcard") {
288
- const url = getAttribute(child, "url");
289
- if (url) {
290
- const ogpData = ogpDataMap.get(url);
291
- const cardElement = ogpData ? createOgpCard(ogpData) : createFallbackCard(url);
292
- node.children[i] = cardElement;
293
- }
294
- } else visit(child);
295
- }
296
- };
297
- visit(tree);
298
- };
299
- }
300
- /**
301
- * Transform OgCard components in HTML.
302
- */
303
- async function transformOgp(html, ogpDataMap, options) {
304
- let dataMap = ogpDataMap;
305
- if (!dataMap) dataMap = await prefetchOgpData(await collectOgpUrls(html), options);
306
- const result = await (0, unified.unified)().use(rehypeParse, { fragment: true }).use(rehypeOgp, dataMap).use(rehypeStringify).process(html);
307
- return String(result);
308
- }
309
- //#endregion
310
- Object.defineProperty(exports, "collectOgpUrls", {
311
- enumerable: true,
312
- get: function() {
313
- return collectOgpUrls;
314
- }
315
- });
316
- Object.defineProperty(exports, "fetchOgpData", {
317
- enumerable: true,
318
- get: function() {
319
- return fetchOgpData;
320
- }
321
- });
322
- Object.defineProperty(exports, "ogp_exports", {
323
- enumerable: true,
324
- get: function() {
325
- return ogp_exports;
326
- }
327
- });
328
- Object.defineProperty(exports, "prefetchOgpData", {
329
- enumerable: true,
330
- get: function() {
331
- return prefetchOgpData;
332
- }
333
- });
334
- Object.defineProperty(exports, "transformOgp", {
335
- enumerable: true,
336
- get: function() {
337
- return transformOgp;
338
- }
339
- });
340
-
341
- //# sourceMappingURL=ogp.cjs.map
package/dist/ogp.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"ogp.cjs","names":["interopDefault","rehypeParsePlugin","rehypeStringifyPlugin"],"sources":["../src/plugins/ogp.ts"],"sourcesContent":["/**\n * OGP Card Plugin - Link card embedding\n *\n * Transforms <OgCard> components into static link preview cards\n * by fetching OGP metadata at build time.\n */\n\nimport { unified } from \"unified\";\nimport rehypeParsePlugin from \"rehype-parse\";\nimport rehypeStringifyPlugin from \"rehype-stringify\";\nimport type { Root, Element } from \"hast\";\nimport { interopDefault } from \"../interop\";\n\n// ESM-only plugins are double-wrapped by the CommonJS interop; unwrap. See #452.\nconst rehypeParse = interopDefault(rehypeParsePlugin);\nconst rehypeStringify = interopDefault(rehypeStringifyPlugin);\n\nexport interface OgpData {\n url: string;\n title: string;\n description?: string;\n image?: string;\n siteName?: string;\n favicon?: string;\n}\n\nexport interface OgpOptions {\n /**\n * Request timeout in milliseconds.\n * @default 10000\n */\n timeout?: number;\n\n /**\n * Cache fetched Open Graph metadata in memory for the current process.\n * @default true\n */\n cache?: boolean;\n\n /**\n * Cache TTL in milliseconds.\n * @default 3600000\n */\n cacheTTL?: number;\n\n /**\n * User agent sent with metadata fetch requests.\n * @default 'ox-content-ogp-bot/1.0 (compatible; +https://github.com/ubugeeei-prod/ox-content)'\n */\n userAgent?: string;\n}\n\nconst defaultOptions: Required<OgpOptions> = {\n timeout: 10000,\n cache: true,\n cacheTTL: 3600000,\n userAgent: \"ox-content-ogp-bot/1.0 (compatible; +https://github.com/ubugeeei-prod/ox-content)\",\n};\n\n// Simple in-memory cache\nconst ogpCache = new Map<string, { data: OgpData; timestamp: number }>();\n\nfunction isPrivateIPv4(hostname: string): boolean {\n const parts = hostname.split(\".\").map(Number);\n if (\n parts.length !== 4 ||\n parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)\n ) {\n return false;\n }\n const [a, b] = parts;\n return (\n a === 10 ||\n a === 127 ||\n a === 0 ||\n (a === 172 && b >= 16 && b <= 31) ||\n (a === 192 && b === 168) ||\n (a === 169 && b === 254)\n );\n}\n\nexport function isSafeOgpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n const host = url.hostname.toLowerCase();\n const ipv6 = host.replace(/^\\[|\\]$/g, \"\");\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return false;\n if (host === \"localhost\" || host.endsWith(\".localhost\")) return false;\n if (\n ipv6.includes(\":\") &&\n (ipv6 === \"::1\" || ipv6.startsWith(\"fc\") || ipv6.startsWith(\"fd\") || ipv6.startsWith(\"fe80\"))\n )\n return false;\n return !isPrivateIPv4(host);\n } catch {\n return false;\n }\n}\n\n/**\n * Get element attribute value.\n */\nfunction getAttribute(el: Element, name: string): string | undefined {\n const value = el.properties?.[name];\n if (typeof value === \"string\") return value;\n if (Array.isArray(value)) return value.join(\" \");\n return undefined;\n}\n\n/**\n * Extract domain from URL.\n */\nfunction extractDomain(url: string): string {\n try {\n const urlObj = new URL(url);\n return urlObj.hostname;\n } catch {\n return url;\n }\n}\n\n/**\n * Get favicon URL for a domain.\n */\nfunction getFaviconUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n // Use Google's favicon service as fallback\n return `https://www.google.com/s2/favicons?domain=${urlObj.hostname}&sz=32`;\n } catch {\n return \"\";\n }\n}\n\n/**\n * Parse OGP metadata from HTML.\n */\nfunction parseOgpFromHtml(html: string, url: string): OgpData {\n const result: OgpData = {\n url,\n title: \"\",\n };\n\n // Extract title\n const titleMatch = html.match(/<title[^>]*>([^<]+)<\\/title>/i);\n const ogTitleMatch =\n html.match(/<meta[^>]*property=[\"']og:title[\"'][^>]*content=[\"']([^\"']+)[\"']/i) ||\n html.match(/<meta[^>]*content=[\"']([^\"']+)[\"'][^>]*property=[\"']og:title[\"']/i);\n\n result.title = ogTitleMatch?.[1] || titleMatch?.[1] || extractDomain(url);\n\n // Extract description\n const descMatch =\n html.match(/<meta[^>]*property=[\"']og:description[\"'][^>]*content=[\"']([^\"']+)[\"']/i) ||\n html.match(/<meta[^>]*content=[\"']([^\"']+)[\"'][^>]*property=[\"']og:description[\"']/i) ||\n html.match(/<meta[^>]*name=[\"']description[\"'][^>]*content=[\"']([^\"']+)[\"']/i) ||\n html.match(/<meta[^>]*content=[\"']([^\"']+)[\"'][^>]*name=[\"']description[\"']/i);\n\n if (descMatch) {\n result.description = descMatch[1];\n }\n\n // Extract image\n const imageMatch =\n html.match(/<meta[^>]*property=[\"']og:image[\"'][^>]*content=[\"']([^\"']+)[\"']/i) ||\n html.match(/<meta[^>]*content=[\"']([^\"']+)[\"'][^>]*property=[\"']og:image[\"']/i);\n\n if (imageMatch) {\n let imageUrl = imageMatch[1];\n // Handle relative URLs\n if (imageUrl.startsWith(\"/\")) {\n try {\n const urlObj = new URL(url);\n imageUrl = `${urlObj.protocol}//${urlObj.host}${imageUrl}`;\n } catch {\n // Keep as is\n }\n }\n result.image = imageUrl;\n }\n\n // Extract site name\n const siteNameMatch =\n html.match(/<meta[^>]*property=[\"']og:site_name[\"'][^>]*content=[\"']([^\"']+)[\"']/i) ||\n html.match(/<meta[^>]*content=[\"']([^\"']+)[\"'][^>]*property=[\"']og:site_name[\"']/i);\n\n if (siteNameMatch) {\n result.siteName = siteNameMatch[1];\n }\n\n // Get favicon\n result.favicon = getFaviconUrl(url);\n\n return result;\n}\n\n/**\n * Fetch OGP data for a URL.\n */\nexport async function fetchOgpData(\n url: string,\n options: Required<OgpOptions>,\n): Promise<OgpData | null> {\n if (!isSafeOgpUrl(url)) {\n return null;\n }\n\n // Check cache\n if (options.cache) {\n const cached = ogpCache.get(url);\n if (cached && Date.now() - cached.timestamp < options.cacheTTL) {\n return cached.data;\n }\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), options.timeout);\n\n const response = await fetch(url, {\n headers: {\n \"User-Agent\": options.userAgent,\n Accept: \"text/html,application/xhtml+xml\",\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n console.warn(`Failed to fetch OGP for ${url}: ${response.status}`);\n return null;\n }\n\n const html = await response.text();\n const data = parseOgpFromHtml(html, url);\n\n // Cache the result\n if (options.cache) {\n ogpCache.set(url, { data, timestamp: Date.now() });\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n console.warn(`Timeout fetching OGP for ${url}`);\n } else {\n console.warn(`Error fetching OGP for ${url}:`, error);\n }\n return null;\n }\n}\n\n/**\n * Create OGP card element.\n */\nfunction createOgpCard(data: OgpData): Element {\n const children: Element[\"children\"] = [];\n\n // Content section\n const contentChildren: Element[\"children\"] = [];\n\n // Title\n contentChildren.push({\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-ogp-title\"] },\n children: [{ type: \"text\", value: data.title }],\n });\n\n // Description\n if (data.description) {\n contentChildren.push({\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-ogp-description\"] },\n children: [{ type: \"text\", value: data.description }],\n });\n }\n\n // Meta (favicon + domain)\n const metaChildren: Element[\"children\"] = [];\n\n if (data.favicon) {\n metaChildren.push({\n type: \"element\",\n tagName: \"img\",\n properties: {\n className: [\"ox-ogp-favicon\"],\n src: data.favicon,\n alt: \"\",\n loading: \"lazy\",\n },\n children: [],\n });\n }\n\n metaChildren.push({\n type: \"element\",\n tagName: \"span\",\n properties: { className: [\"ox-ogp-domain\"] },\n children: [{ type: \"text\", value: data.siteName || extractDomain(data.url) }],\n });\n\n contentChildren.push({\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-ogp-meta\"] },\n children: metaChildren,\n });\n\n children.push({\n type: \"element\",\n tagName: \"div\",\n properties: { className: [\"ox-ogp-content\"] },\n children: contentChildren,\n });\n\n // Image\n if (data.image) {\n children.push({\n type: \"element\",\n tagName: \"img\",\n properties: {\n className: [\"ox-ogp-image\"],\n src: data.image,\n alt: \"\",\n loading: \"lazy\",\n },\n children: [],\n });\n }\n\n return {\n type: \"element\",\n tagName: \"a\",\n properties: {\n className: [\"ox-ogp-card\"],\n href: isSafeOgpUrl(data.url) ? data.url : \"#\",\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n children,\n };\n}\n\n/**\n * Create fallback element when OGP data is unavailable.\n */\nfunction createFallbackCard(url: string): Element {\n return {\n type: \"element\",\n tagName: \"a\",\n properties: {\n className: [\"ox-ogp-simple\"],\n href: isSafeOgpUrl(url) ? url : \"#\",\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n children: [\n {\n type: \"element\",\n tagName: \"svg\",\n properties: {\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n },\n children: [\n {\n type: \"element\",\n tagName: \"path\",\n properties: {\n d: \"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3\",\n },\n children: [],\n },\n ],\n },\n { type: \"text\", value: extractDomain(url) },\n ],\n };\n}\n\n/**\n * Collect all OGP URLs from HTML for pre-fetching.\n */\nexport async function collectOgpUrls(html: string): Promise<string[]> {\n const urls: string[] = [];\n const urlPattern = /<ogcard[^>]*\\s+url=[\"']([^\"']+)[\"']/gi;\n\n let match;\n while ((match = urlPattern.exec(html)) !== null) {\n if (isSafeOgpUrl(match[1])) {\n urls.push(match[1]);\n }\n }\n\n return urls;\n}\n\n/**\n * Pre-fetch all OGP data.\n */\nexport async function prefetchOgpData(\n urls: string[],\n options?: OgpOptions,\n): Promise<Map<string, OgpData | null>> {\n const mergedOptions = { ...defaultOptions, ...options };\n const results = new Map<string, OgpData | null>();\n\n await Promise.all(\n urls.map(async (url) => {\n const data = await fetchOgpData(url, mergedOptions);\n results.set(url, data);\n }),\n );\n\n return results;\n}\n\n/**\n * Rehype plugin to transform OgCard components.\n */\nfunction rehypeOgp(ogpDataMap: Map<string, OgpData | null>) {\n return (tree: Root) => {\n const visit = (node: Root | Element) => {\n if (\"children\" in node) {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n\n if (child.type === \"element\") {\n // Check for <OgCard> component\n if (child.tagName.toLowerCase() === \"ogcard\") {\n const url = getAttribute(child, \"url\");\n\n if (url) {\n const ogpData = ogpDataMap.get(url);\n const cardElement = ogpData ? createOgpCard(ogpData) : createFallbackCard(url);\n node.children[i] = cardElement;\n }\n } else {\n visit(child);\n }\n }\n }\n }\n };\n\n visit(tree);\n };\n}\n\n/**\n * Transform OgCard components in HTML.\n */\nexport async function transformOgp(\n html: string,\n ogpDataMap?: Map<string, OgpData | null>,\n options?: OgpOptions,\n): Promise<string> {\n // If no pre-fetched data, collect and fetch\n let dataMap = ogpDataMap;\n if (!dataMap) {\n const urls = await collectOgpUrls(html);\n dataMap = await prefetchOgpData(urls, options);\n }\n\n const result = await unified()\n .use(rehypeParse, { fragment: true })\n .use(rehypeOgp, dataMap)\n .use(rehypeStringify)\n .process(html);\n\n return String(result);\n}\n"],"mappings":"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"}
package/dist/ogp.mjs DELETED
@@ -1,2 +0,0 @@
1
- import { a as transformOgp } from "./ogp2.mjs";
2
- export { transformOgp };