@coywolf/emdash 0.0.0-stage → 0.35.13

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 (261) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -2
  3. package/package.json +70 -5
  4. package/src/admin/admin-css.ts +57 -0
  5. package/src/admin/ai.tsx +915 -0
  6. package/src/admin/backups.tsx +613 -0
  7. package/src/admin/breadcrumbs.tsx +542 -0
  8. package/src/admin/codeBlocks.tsx +204 -0
  9. package/src/admin/customBlocks.tsx +321 -0
  10. package/src/admin/dirty.ts +20 -0
  11. package/src/admin/discovery.tsx +463 -0
  12. package/src/admin/download.ts +28 -0
  13. package/src/admin/feature-switches.tsx +124 -0
  14. package/src/admin/features.tsx +142 -0
  15. package/src/admin/files.tsx +791 -0
  16. package/src/admin/formUploads.tsx +445 -0
  17. package/src/admin/guides.tsx +18 -0
  18. package/src/admin/headings.tsx +262 -0
  19. package/src/admin/images.tsx +825 -0
  20. package/src/admin/index.tsx +62 -0
  21. package/src/admin/links.tsx +980 -0
  22. package/src/admin/performance.tsx +330 -0
  23. package/src/admin/preview.tsx +63 -0
  24. package/src/admin/redirects-removed.tsx +266 -0
  25. package/src/admin/redirects.tsx +470 -0
  26. package/src/admin/reviews.tsx +232 -0
  27. package/src/admin/robots-bots.tsx +647 -0
  28. package/src/admin/robots-shared.tsx +109 -0
  29. package/src/admin/robots-wizard.tsx +748 -0
  30. package/src/admin/robots.tsx +911 -0
  31. package/src/admin/save-bar.tsx +134 -0
  32. package/src/admin/schema.tsx +1187 -0
  33. package/src/admin/search.tsx +355 -0
  34. package/src/admin/settings-ui.tsx +87 -0
  35. package/src/admin/trash-prompt-core.ts +135 -0
  36. package/src/admin/trash-prompt.tsx +156 -0
  37. package/src/admin/usage.tsx +301 -0
  38. package/src/admin/videos-display.tsx +248 -0
  39. package/src/admin/videos.tsx +1202 -0
  40. package/src/admin/wpImport.tsx +1516 -0
  41. package/src/ai/entities.ts +59 -0
  42. package/src/ai/export.ts +61 -0
  43. package/src/ai/logic.test.ts +187 -0
  44. package/src/ai/logic.ts +606 -0
  45. package/src/ai/pack.ts +121 -0
  46. package/src/ai/prompts.ts +87 -0
  47. package/src/ai/providers.ts +276 -0
  48. package/src/ai/queue.test.ts +97 -0
  49. package/src/ai/routes.ts +359 -0
  50. package/src/ai/store.ts +301 -0
  51. package/src/ai/wikidata.test.ts +184 -0
  52. package/src/ai/wikidata.ts +87 -0
  53. package/src/ai/worker.ts +530 -0
  54. package/src/astro/astro-modules.d.ts +6 -0
  55. package/src/astro/breadcrumbs/Breadcrumbs.astro +129 -0
  56. package/src/astro/breadcrumbs/BreadcrumbsBlock.astro +12 -0
  57. package/src/astro/codeBlocks/CodeBlock.astro +62 -0
  58. package/src/astro/codeBlocks/EmDashCode.astro +61 -0
  59. package/src/astro/customBlocks/CustomBlock.astro +64 -0
  60. package/src/astro/customBlocks/Details.astro +8 -0
  61. package/src/astro/customBlocks/Disclosure.astro +8 -0
  62. package/src/astro/customBlocks/Note.astro +8 -0
  63. package/src/astro/customBlocks/Podcast.astro +8 -0
  64. package/src/astro/customBlocks/Quote.astro +8 -0
  65. package/src/astro/customBlocks/Testimonial.astro +8 -0
  66. package/src/astro/files/FileCard.astro +103 -0
  67. package/src/astro/headings/HeadingBlock.astro +129 -0
  68. package/src/astro/headings/TableOfContents.astro +45 -0
  69. package/src/astro/headings/request.ts +19 -0
  70. package/src/astro/images/ResponsiveImage.astro +60 -0
  71. package/src/astro/index.ts +84 -0
  72. package/src/astro/reviews/CoywolfReview.astro +27 -0
  73. package/src/astro/reviews/Review.astro +49 -0
  74. package/src/astro/search/SearchBox.astro +61 -0
  75. package/src/astro/search/SearchBoxForm.astro +509 -0
  76. package/src/astro/tables/CaptionedTable.astro +72 -0
  77. package/src/astro/videos/CoywolfVideo.astro +448 -0
  78. package/src/backups/download.ts +112 -0
  79. package/src/backups/dump.test.mjs +287 -0
  80. package/src/backups/dump.ts +288 -0
  81. package/src/backups/module.ts +276 -0
  82. package/src/backups/pack.ts +33 -0
  83. package/src/backups/restore.test.mjs +103 -0
  84. package/src/backups/restore.ts +209 -0
  85. package/src/backups/store.ts +409 -0
  86. package/src/breadcrumbs/pack.ts +113 -0
  87. package/src/breadcrumbs/settings.ts +102 -0
  88. package/src/breadcrumbs/stamp.ts +40 -0
  89. package/src/breadcrumbs/trail.ts +123 -0
  90. package/src/codeBlocks/contrast.ts +179 -0
  91. package/src/codeBlocks/hljs.d.ts +5 -0
  92. package/src/codeBlocks/pack.ts +110 -0
  93. package/src/codeBlocks/render.test.ts +152 -0
  94. package/src/codeBlocks/render.ts +304 -0
  95. package/src/codeBlocks/settings.ts +18 -0
  96. package/src/codeBlocks/themes.generated.ts +304 -0
  97. package/src/codeBlocks/themes.ts +114 -0
  98. package/src/core/compose.ts +244 -0
  99. package/src/core/content-url.ts +888 -0
  100. package/src/core/csv.ts +119 -0
  101. package/src/core/d1-batch.ts +65 -0
  102. package/src/core/entry-docs.ts +175 -0
  103. package/src/core/features-module.ts +48 -0
  104. package/src/core/features.ts +392 -0
  105. package/src/core/generation.ts +88 -0
  106. package/src/core/guide-content.ts +166 -0
  107. package/src/core/module.ts +104 -0
  108. package/src/core/read-failures.ts +57 -0
  109. package/src/core/request-memo.ts +71 -0
  110. package/src/core/secrets.ts +83 -0
  111. package/src/core/settings-enhance.ts +74 -0
  112. package/src/core/site.ts +36 -0
  113. package/src/core/storage.ts +27 -0
  114. package/src/customBlocks/pack.ts +260 -0
  115. package/src/customBlocks/render.ts +424 -0
  116. package/src/customBlocks/rich.ts +313 -0
  117. package/src/customBlocks/settings.ts +46 -0
  118. package/src/discovery/build.ts +252 -0
  119. package/src/discovery/feed-build.ts +217 -0
  120. package/src/discovery/feed.ts +172 -0
  121. package/src/discovery/indexnow.ts +114 -0
  122. package/src/discovery/llms.ts +79 -0
  123. package/src/discovery/markdown.ts +294 -0
  124. package/src/discovery/memory-cache.ts +97 -0
  125. package/src/discovery/middleware.ts +186 -0
  126. package/src/discovery/module.ts +353 -0
  127. package/src/discovery/news.ts +99 -0
  128. package/src/discovery/pack.ts +58 -0
  129. package/src/discovery/settings.ts +91 -0
  130. package/src/discovery/urls.ts +35 -0
  131. package/src/env.d.ts +10 -0
  132. package/src/files/card.ts +231 -0
  133. package/src/files/counts.test.ts +114 -0
  134. package/src/files/counts.ts +60 -0
  135. package/src/files/export.ts +44 -0
  136. package/src/files/format.test.ts +93 -0
  137. package/src/files/format.ts +163 -0
  138. package/src/files/module.ts +596 -0
  139. package/src/files/pack.ts +92 -0
  140. package/src/files/r2-rules.test.ts +30 -0
  141. package/src/files/r2-rules.ts +41 -0
  142. package/src/files/range.ts +50 -0
  143. package/src/files/s3.ts +114 -0
  144. package/src/files/serve.ts +141 -0
  145. package/src/files/sigv4.test.ts +64 -0
  146. package/src/files/sigv4.ts +160 -0
  147. package/src/files/site.ts +137 -0
  148. package/src/files/walker.ts +58 -0
  149. package/src/formUploads/lib.ts +266 -0
  150. package/src/formUploads/pack.ts +55 -0
  151. package/src/formUploads/wrap.ts +592 -0
  152. package/src/forms.ts +16 -0
  153. package/src/headings/headings.test.ts +159 -0
  154. package/src/headings/pack.ts +154 -0
  155. package/src/headings/render.ts +139 -0
  156. package/src/headings/settings.ts +117 -0
  157. package/src/headings/slug.ts +68 -0
  158. package/src/headings/stamp.ts +142 -0
  159. package/src/headings/test-hooks.mjs +14 -0
  160. package/src/headings/toc.ts +48 -0
  161. package/src/images/cloudflare.ts +329 -0
  162. package/src/images/lib.ts +221 -0
  163. package/src/images/module.ts +372 -0
  164. package/src/images/pack.ts +804 -0
  165. package/src/images/pending.ts +37 -0
  166. package/src/images/settings.ts +48 -0
  167. package/src/images/setup.ts +192 -0
  168. package/src/images/variants-estimate.ts +162 -0
  169. package/src/images/variants-store.ts +475 -0
  170. package/src/images/variants.ts +311 -0
  171. package/src/index.ts +143 -0
  172. package/src/links/check.ts +101 -0
  173. package/src/links/classify.ts +270 -0
  174. package/src/links/export.ts +59 -0
  175. package/src/links/module.ts +652 -0
  176. package/src/links/pack.ts +43 -0
  177. package/src/links/pt.ts +325 -0
  178. package/src/links/store.ts +704 -0
  179. package/src/middleware.ts +287 -0
  180. package/src/modules.ts +53 -0
  181. package/src/options.ts +66 -0
  182. package/src/pageCache/lib.test.mjs +224 -0
  183. package/src/pageCache/lib.ts +274 -0
  184. package/src/pageCache/pack.ts +240 -0
  185. package/src/pageCache/usage-core.ts +152 -0
  186. package/src/pageCache/usage.ts +262 -0
  187. package/src/pageCache/warm.test.mjs +670 -0
  188. package/src/pageCache/warm.ts +722 -0
  189. package/src/redirects/middleware.ts +169 -0
  190. package/src/redirects/module.ts +124 -0
  191. package/src/redirects/pack.ts +89 -0
  192. package/src/redirects/removed-core.ts +151 -0
  193. package/src/redirects/removed.ts +293 -0
  194. package/src/redirects/rules.ts +355 -0
  195. package/src/redirects/slug-changes.ts +207 -0
  196. package/src/redirects/slug-core.test.ts +50 -0
  197. package/src/redirects/slug-core.ts +49 -0
  198. package/src/redirects/transfer.ts +92 -0
  199. package/src/reviews/lib.ts +624 -0
  200. package/src/reviews/pack.ts +135 -0
  201. package/src/reviews/schema.ts +128 -0
  202. package/src/reviews/settings.ts +26 -0
  203. package/src/robots/bots.ts +321 -0
  204. package/src/robots/data/bots.json +696 -0
  205. package/src/robots/data/verified.json +582 -0
  206. package/src/robots/directory.ts +26 -0
  207. package/src/robots/explain.ts +191 -0
  208. package/src/robots/guided.ts +300 -0
  209. package/src/robots/importer.ts +263 -0
  210. package/src/robots/middleware.ts +151 -0
  211. package/src/robots/module.ts +446 -0
  212. package/src/robots/pack.ts +69 -0
  213. package/src/robots/radar.ts +129 -0
  214. package/src/robots/rep.test.ts +335 -0
  215. package/src/robots/rep.ts +362 -0
  216. package/src/robots/rules.test.ts +251 -0
  217. package/src/robots/rules.ts +883 -0
  218. package/src/robots/transfer.ts +45 -0
  219. package/src/robots/validate.ts +524 -0
  220. package/src/schema/catalog.ts +146 -0
  221. package/src/schema/graph.test.mjs +522 -0
  222. package/src/schema/graph.ts +791 -0
  223. package/src/schema/module.ts +1138 -0
  224. package/src/schema/og-image.ts +100 -0
  225. package/src/schema/pack.ts +58 -0
  226. package/src/search/engine.ts +578 -0
  227. package/src/search/fallback.ts +80 -0
  228. package/src/search/live-cache.ts +116 -0
  229. package/src/search/live-client.ts +770 -0
  230. package/src/search/live-serve.ts +282 -0
  231. package/src/search/module.ts +261 -0
  232. package/src/search/pack.ts +57 -0
  233. package/src/search/query.ts +132 -0
  234. package/src/search/ratelimit-core.ts +118 -0
  235. package/src/search/ratelimit.ts +79 -0
  236. package/src/search/snippet.ts +135 -0
  237. package/src/search/title-index.ts +139 -0
  238. package/src/search/title-match.ts +192 -0
  239. package/src/shared.ts +71 -0
  240. package/src/version.ts +2 -0
  241. package/src/videos/date.ts +40 -0
  242. package/src/videos/engagement.ts +75 -0
  243. package/src/videos/lib.ts +679 -0
  244. package/src/videos/module.ts +1160 -0
  245. package/src/videos/pack.ts +187 -0
  246. package/src/videos/pause.ts +42 -0
  247. package/src/videos/poster.ts +324 -0
  248. package/src/videos/render.ts +336 -0
  249. package/src/videos/store.ts +551 -0
  250. package/src/videos/stream.ts +134 -0
  251. package/src/wpImport/convert.ts +702 -0
  252. package/src/wpImport/guests.ts +329 -0
  253. package/src/wpImport/gutenberg.ts +157 -0
  254. package/src/wpImport/markers.ts +66 -0
  255. package/src/wpImport/pack.ts +451 -0
  256. package/src/wpImport/parents.ts +202 -0
  257. package/src/wpImport/prepare.ts +592 -0
  258. package/src/wpImport/redirects.ts +358 -0
  259. package/src/wpImport/sources.ts +67 -0
  260. package/src/wpImport/stream.ts +160 -0
  261. package/src/wpImport/urls.ts +354 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The page's og:image with Clean image URLs on: the default OG image at a
3
+ * clean 1200x630 URL, the page's own media-library image as the original
4
+ * file on the media host, and the Open Graph tags for it. Pure (no I/O), so
5
+ * tests can load it; the media lookups are in module.ts.
6
+ */
7
+ import type { PageMetadataContribution } from "emdash";
8
+
9
+ import { FORMATS, cdnOriginalUrl, cleanImagePath, imageCdn, mediaFile, mimeForExt, parseCdnUrl, parseImagePath } from "../images/lib.js";
10
+ import { type ImageInfo, absolute } from "./graph.js";
11
+
12
+ export const OG_WIDTH = 1200;
13
+ export const OG_HEIGHT = 630;
14
+
15
+ /**
16
+ * The site's default OG image as a clean 1200x630 URL. On the media host,
17
+ * /s/1200x630/<file> (the host serves the original format to crawlers that
18
+ * don't ask for WebP or AVIF, so the type is the original's). Otherwise the
19
+ * Worker route, where PNG stays PNG and anything else becomes JPEG. Null when
20
+ * it isn't a (raster) media-library image.
21
+ */
22
+ export function cleanDefaultOgImage(defaultOg: ImageInfo | null | undefined, origin: string): ImageInfo | null {
23
+ if (!defaultOg) return null;
24
+ const file = mediaFile(defaultOg.url);
25
+ if (!file || file.ext === "svg") return null;
26
+ if (imageCdn()) {
27
+ const url = cleanImagePath(defaultOg.url, { width: OG_WIDTH, height: OG_HEIGHT });
28
+ return url ? { url, width: OG_WIDTH, height: OG_HEIGHT, alt: defaultOg.alt, mimeType: mimeForExt(file.ext) } : null;
29
+ }
30
+ const format = file.ext === "png" ? "png" : "jpg";
31
+ const path = cleanImagePath(defaultOg.url, { width: OG_WIDTH, height: OG_HEIGHT, format });
32
+ if (!path) return null;
33
+ return { url: absolute(path, origin) ?? path, width: OG_WIDTH, height: OG_HEIGHT, alt: defaultOg.alt, mimeType: FORMATS[format] };
34
+ }
35
+
36
+ /** The page's own image (a media-library file) as its original on the media host; null without a host or for anything else. */
37
+ export function ownImageOnMediaHost(own: string | null | undefined): string | null {
38
+ return mediaFile(own) ? cdnOriginalUrl(own) : null;
39
+ }
40
+
41
+ /** A media item's row from the media table. */
42
+ export interface MediaRow {
43
+ width: number | null;
44
+ height: number | null;
45
+ alt: string | null;
46
+ mime_type?: string | null;
47
+ }
48
+
49
+ /**
50
+ * Image facts for a media-host URL: the requested size (width-only keeps the
51
+ * original ratio; the original keeps its own size) and the original file's
52
+ * type. Null when the URL isn't on the media host.
53
+ */
54
+ export function mediaHostImageInfo(url: string, row: MediaRow): ImageInfo | null {
55
+ const parsed = parseCdnUrl(url);
56
+ if (!parsed) return null;
57
+ let width: number | null = row.width;
58
+ let height: number | null = row.height;
59
+ if (parsed.width !== undefined) {
60
+ width = parsed.width;
61
+ height = parsed.height ?? (row.width && row.height ? Math.round((parsed.width * row.height) / row.width) : null);
62
+ }
63
+ return { url, width, height, alt: row.alt, mimeType: mimeForExt(parsed.ext) ?? row.mime_type ?? undefined };
64
+ }
65
+
66
+ /**
67
+ * Whether the pack outputs og:image/twitter:image itself (so they win over
68
+ * EmDash's, first contribution wins): for media-host URLs, and for the
69
+ * default image at its Worker-route clean URL. EmDash's own tags stay for
70
+ * everything else, so there's never a second og:image.
71
+ */
72
+ export function packOwnsOgImage(url: string, origin: string, hasOwnImage: boolean): boolean {
73
+ if (parseCdnUrl(url)) return true;
74
+ if (hasOwnImage) return false;
75
+ try {
76
+ return parseImagePath(new URL(url, origin || "https://site.invalid").pathname) !== null;
77
+ } catch {
78
+ return false;
79
+ }
80
+ }
81
+
82
+ /** og:image (when the pack owns it), its size, type and alt, and twitter:image(:alt). */
83
+ export function ogImageTags(image: ImageInfo | null, ownsUrl: boolean): PageMetadataContribution[] {
84
+ const out: PageMetadataContribution[] = [];
85
+ if (!image) return out;
86
+ if (ownsUrl) {
87
+ out.push({ kind: "property", property: "og:image", content: image.url });
88
+ out.push({ kind: "meta", name: "twitter:image", content: image.url });
89
+ }
90
+ if (image.width && image.height) {
91
+ out.push({ kind: "property", property: "og:image:width", content: String(image.width) });
92
+ out.push({ kind: "property", property: "og:image:height", content: String(image.height) });
93
+ }
94
+ if (image.mimeType?.startsWith("image/")) out.push({ kind: "property", property: "og:image:type", content: image.mimeType });
95
+ if (image.alt?.trim()) {
96
+ out.push({ kind: "property", property: "og:image:alt", content: image.alt.trim() });
97
+ out.push({ kind: "meta", name: "twitter:image:alt", content: image.alt.trim() });
98
+ }
99
+ return out;
100
+ }
@@ -0,0 +1,58 @@
1
+ import { registerFeatures } from "../core/features.js";
2
+ import type { PackModule } from "../core/module.js";
3
+ import { type SchemaOptions, schemaMetadataHook, schemaModule, schemaStorage } from "./module.js";
4
+
5
+ const FEATURES = [
6
+ {
7
+ id: "schema",
8
+ label: "Schema & Social",
9
+ description: "Schema.org structured data, robots directives, and Open Graph extras, configured on the Schema page.",
10
+ default: false,
11
+ },
12
+ {
13
+ id: "schema.graph",
14
+ label: "Schema.org graph",
15
+ description:
16
+ "One JSON-LD @graph per page (WebSite, publisher, typed WebPage and Article, authors, image) in place of EmDash's built-in JSON-LD.",
17
+ default: false,
18
+ },
19
+ {
20
+ id: "schema.breadcrumbs",
21
+ label: "Breadcrumb schema",
22
+ description:
23
+ "A BreadcrumbList from the theme's breadcrumbs, or derived from the URL. Remove any BreadcrumbList your theme prints itself.",
24
+ default: false,
25
+ },
26
+ {
27
+ id: "schema.robots",
28
+ label: "Robots directives",
29
+ description: "A robots meta tag with max-image-preview, max-snippet and max-video-preview, merged with each entry's No index.",
30
+ default: false,
31
+ },
32
+ {
33
+ id: "schema.openGraph",
34
+ label: "Open Graph extras",
35
+ description: "og:locale, plus og:image width, height, type and alt (from the media library) and twitter:image:alt.",
36
+ default: false,
37
+ },
38
+ {
39
+ id: "schema.authors",
40
+ label: "Author profiles",
41
+ description: "Schema.org Person properties per byline (job title, sameAs profiles, image…) used as article authors.",
42
+ default: false,
43
+ },
44
+ ];
45
+ registerFeatures(FEATURES);
46
+
47
+ export function schemaPack(options: SchemaOptions): PackModule {
48
+ return {
49
+ id: "schema",
50
+ label: "Schema & Social",
51
+ features: FEATURES,
52
+ routes: schemaModule(options).routes,
53
+ hooks: { "page:metadata": schemaMetadataHook(options) },
54
+ adminPages: [{ path: "/schema", label: "Schema", icon: "tree-structure" }],
55
+ storage: schemaStorage,
56
+ capabilities: ["content:read", "schema:read", "bylines:read", "media:read"],
57
+ };
58
+ }