@dxos/plugin-magazine 0.10.0 → 0.11.0

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 (242) hide show
  1. package/dist/lib/MagazinePlugin.mjs +36 -0
  2. package/dist/lib/MagazinePlugin.mjs.map +1 -0
  3. package/dist/lib/MagazinePlugin.workerd.mjs +26 -0
  4. package/dist/lib/MagazinePlugin.workerd.mjs.map +1 -0
  5. package/dist/lib/atoms.mjs +175 -0
  6. package/dist/lib/atoms.mjs.map +1 -0
  7. package/dist/lib/capabilities.mjs +12 -0
  8. package/dist/lib/capabilities.mjs.map +1 -0
  9. package/dist/lib/chunk-FeedArticle.mjs +70 -0
  10. package/dist/lib/chunk-FeedArticle.mjs.map +1 -0
  11. package/dist/lib/chunk-FeedProperties.mjs +78 -0
  12. package/dist/lib/chunk-FeedProperties.mjs.map +1 -0
  13. package/dist/lib/chunk-MagazineArticle.mjs +267 -0
  14. package/dist/lib/chunk-MagazineArticle.mjs.map +1 -0
  15. package/dist/lib/chunk-PostArticle.mjs +174 -0
  16. package/dist/lib/chunk-PostArticle.mjs.map +1 -0
  17. package/dist/lib/chunk-PostCard.mjs +62 -0
  18. package/dist/lib/chunk-PostCard.mjs.map +1 -0
  19. package/dist/lib/chunk-app-graph-builder.mjs +91 -0
  20. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
  21. package/dist/lib/chunk-clear-magazine.mjs +37 -0
  22. package/dist/lib/chunk-clear-magazine.mjs.map +1 -0
  23. package/dist/lib/chunk-create-object.mjs +59 -0
  24. package/dist/lib/chunk-create-object.mjs.map +1 -0
  25. package/dist/lib/chunk-curate-magazine.mjs +164 -0
  26. package/dist/lib/chunk-curate-magazine.mjs.map +1 -0
  27. package/dist/lib/chunk-date.mjs +25 -0
  28. package/dist/lib/chunk-date.mjs.map +1 -0
  29. package/dist/lib/chunk-fetch-article-content.mjs +26 -0
  30. package/dist/lib/chunk-fetch-article-content.mjs.map +1 -0
  31. package/dist/lib/chunk-load-post-content.mjs +57 -0
  32. package/dist/lib/chunk-load-post-content.mjs.map +1 -0
  33. package/dist/lib/{neutral/chunk-JFPR6OV4.mjs → chunk-meta.mjs} +19 -26
  34. package/dist/lib/chunk-meta.mjs.map +1 -0
  35. package/dist/lib/chunk-operation-handler.mjs +13 -0
  36. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  37. package/dist/lib/chunk-paths.mjs +8 -0
  38. package/dist/lib/chunk-paths.mjs.map +1 -0
  39. package/dist/lib/chunk-post-content.mjs +14 -0
  40. package/dist/lib/chunk-post-content.mjs.map +1 -0
  41. package/dist/lib/chunk-react-surface.mjs +60 -0
  42. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  43. package/dist/lib/chunk-routine-templates.mjs +52 -0
  44. package/dist/lib/chunk-routine-templates.mjs.map +1 -0
  45. package/dist/lib/chunk-skill-definition.mjs +12 -0
  46. package/dist/lib/chunk-skill-definition.mjs.map +1 -0
  47. package/dist/lib/chunk-sources.mjs +576 -0
  48. package/dist/lib/chunk-sources.mjs.map +1 -0
  49. package/dist/lib/chunk-sync-feed.mjs +86 -0
  50. package/dist/lib/chunk-sync-feed.mjs.map +1 -0
  51. package/dist/lib/chunk-text.mjs +52 -0
  52. package/dist/lib/chunk-text.mjs.map +1 -0
  53. package/dist/lib/chunk-types.mjs +607 -0
  54. package/dist/lib/chunk-types.mjs.map +1 -0
  55. package/dist/lib/components.mjs +323 -0
  56. package/dist/lib/components.mjs.map +1 -0
  57. package/dist/lib/containers.mjs +11 -0
  58. package/dist/lib/containers.mjs.map +1 -0
  59. package/dist/lib/index.mjs +3 -0
  60. package/dist/lib/meta.mjs +2 -0
  61. package/dist/lib/operations.mjs +7 -0
  62. package/dist/lib/operations.mjs.map +1 -0
  63. package/dist/lib/plugin.mjs +9 -0
  64. package/dist/lib/plugin.mjs.map +1 -0
  65. package/dist/lib/plugin.workerd.mjs +3 -0
  66. package/dist/lib/{neutral/skills/index.mjs → skills.mjs} +15 -28
  67. package/dist/lib/skills.mjs.map +1 -0
  68. package/dist/lib/testing.mjs +71 -0
  69. package/dist/lib/testing.mjs.map +1 -0
  70. package/dist/lib/translations.mjs +74 -0
  71. package/dist/lib/translations.mjs.map +1 -0
  72. package/dist/lib/types.mjs +2 -0
  73. package/dist/types/src/MagazinePlugin.d.ts.map +1 -1
  74. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  75. package/dist/types/src/capabilities/create-object.d.ts +1 -1
  76. package/dist/types/src/capabilities/index.d.ts +0 -1
  77. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  79. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  80. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/routine-templates.d.ts +1 -1
  82. package/dist/types/src/components/PostContent/PostContent.d.ts +1 -13
  83. package/dist/types/src/components/PostContent/PostContent.d.ts.map +1 -1
  84. package/dist/types/src/components/PostContent/dedupe-images.d.ts +13 -0
  85. package/dist/types/src/components/PostContent/dedupe-images.d.ts.map +1 -0
  86. package/dist/types/src/components/PostContent/index.d.ts +1 -0
  87. package/dist/types/src/components/PostContent/index.d.ts.map +1 -1
  88. package/dist/types/src/components/PostStack/PostStack.d.ts +1 -1
  89. package/dist/types/src/components/PostStack/PostStack.d.ts.map +1 -1
  90. package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts +1 -1
  91. package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts.map +1 -1
  92. package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts +4 -1
  93. package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts.map +1 -1
  94. package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts +4 -1
  95. package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts.map +1 -1
  96. package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts +4 -1
  97. package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts.map +1 -1
  98. package/dist/types/src/containers/MagazineArticle/MagazineArticle.stories.d.ts.map +1 -1
  99. package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts +4 -1
  100. package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts.map +1 -1
  101. package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts +4 -8
  102. package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts.map +1 -1
  103. package/dist/types/src/containers/PostArticle/PostArticle.d.ts +4 -1
  104. package/dist/types/src/containers/PostArticle/PostArticle.d.ts.map +1 -1
  105. package/dist/types/src/containers/PostArticle/PostArticle.stories.d.ts.map +1 -1
  106. package/dist/types/src/containers/PostArticle/PostToolbar.d.ts +1 -1
  107. package/dist/types/src/containers/PostArticle/PostToolbar.d.ts.map +1 -1
  108. package/dist/types/src/containers/PostCard/PostCard.d.ts +4 -6
  109. package/dist/types/src/containers/PostCard/PostCard.d.ts.map +1 -1
  110. package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts +4 -1
  111. package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts.map +1 -1
  112. package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.d.ts.map +1 -1
  113. package/dist/types/src/stories/ArticleExtractor.stories.d.ts +1 -0
  114. package/dist/types/src/stories/ArticleExtractor.stories.d.ts.map +1 -1
  115. package/dist/types/src/stories/MagazineCurate.stories.d.ts.map +1 -1
  116. package/dist/types/src/templates/magazine-curation.d.ts.map +1 -1
  117. package/dist/types/src/translations.d.ts +1 -0
  118. package/dist/types/src/translations.d.ts.map +1 -1
  119. package/dist/types/tsconfig.tsbuildinfo +1 -1
  120. package/dx.config.ts +1 -1
  121. package/package.json +57 -60
  122. package/src/MagazinePlugin.tsx +0 -3
  123. package/src/atoms/atoms.test.ts +5 -4
  124. package/src/capabilities/app-graph-builder.ts +8 -6
  125. package/src/capabilities/index.ts +0 -1
  126. package/src/capabilities/{react-surface.tsx → react-surface.ts} +10 -12
  127. package/src/components/PostContent/PostContent.test.ts +1 -1
  128. package/src/components/PostContent/PostContent.tsx +1 -41
  129. package/src/components/PostContent/dedupe-images.ts +48 -0
  130. package/src/components/PostContent/index.ts +1 -0
  131. package/src/containers/FeedArticle/FeedArticle.stories.tsx +2 -2
  132. package/src/containers/FeedArticle/FeedArticle.tsx +4 -2
  133. package/src/containers/FeedProperties/FeedProperties.tsx +6 -4
  134. package/src/containers/MagazineArticle/MagazineArticle.stories.tsx +2 -1
  135. package/src/containers/MagazineArticle/MagazineArticle.tsx +8 -6
  136. package/src/containers/MagazineArticle/MagazineTile.tsx +2 -0
  137. package/src/containers/MagazineArticle/useToolbar.tsx +2 -0
  138. package/src/containers/PostArticle/PostArticle.stories.tsx +2 -1
  139. package/src/containers/PostArticle/PostArticle.tsx +6 -3
  140. package/src/containers/PostArticle/PostToolbar.tsx +1 -1
  141. package/src/containers/PostCard/PostCard.tsx +3 -1
  142. package/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.tsx +2 -1
  143. package/src/containers/SubscriptionsArticle/SubscriptionsArticle.tsx +5 -3
  144. package/src/operations/curate-magazine.test.ts +108 -4
  145. package/src/operations/sync-feed.test.ts +1 -1
  146. package/src/operations/sync-feed.ts +1 -1
  147. package/src/paths.ts +3 -3
  148. package/src/stories/ArticleExtractor.stories.tsx +1 -1
  149. package/src/stories/MagazineCurate.stories.tsx +3 -2
  150. package/src/templates/magazine-curation.ts +3 -2
  151. package/src/types/Magazine.test.ts +1 -1
  152. package/src/types/Subscription.ts +1 -1
  153. package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs +0 -90
  154. package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs.map +0 -7
  155. package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs +0 -97
  156. package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs.map +0 -7
  157. package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs +0 -325
  158. package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs.map +0 -7
  159. package/dist/lib/neutral/MagazinePlugin.mjs +0 -62
  160. package/dist/lib/neutral/MagazinePlugin.mjs.map +0 -7
  161. package/dist/lib/neutral/MagazinePlugin.workerd.mjs +0 -12
  162. package/dist/lib/neutral/MagazinePlugin.workerd.mjs.map +0 -7
  163. package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs +0 -230
  164. package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs.map +0 -7
  165. package/dist/lib/neutral/PostCard-VDGN7BBA.mjs +0 -60
  166. package/dist/lib/neutral/PostCard-VDGN7BBA.mjs.map +0 -7
  167. package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs +0 -121
  168. package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs.map +0 -7
  169. package/dist/lib/neutral/capabilities/index.mjs +0 -21
  170. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  171. package/dist/lib/neutral/chunk-3K4AQKBZ.mjs +0 -12
  172. package/dist/lib/neutral/chunk-3K4AQKBZ.mjs.map +0 -7
  173. package/dist/lib/neutral/chunk-AFPBWBTK.mjs +0 -591
  174. package/dist/lib/neutral/chunk-AFPBWBTK.mjs.map +0 -7
  175. package/dist/lib/neutral/chunk-APQRTYT3.mjs +0 -57
  176. package/dist/lib/neutral/chunk-APQRTYT3.mjs.map +0 -7
  177. package/dist/lib/neutral/chunk-GU725ZF4.mjs +0 -11
  178. package/dist/lib/neutral/chunk-GU725ZF4.mjs.map +0 -7
  179. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  180. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  181. package/dist/lib/neutral/chunk-JFPR6OV4.mjs.map +0 -7
  182. package/dist/lib/neutral/chunk-KTYLUOUG.mjs +0 -36
  183. package/dist/lib/neutral/chunk-KTYLUOUG.mjs.map +0 -7
  184. package/dist/lib/neutral/chunk-LFSQMLPK.mjs +0 -8
  185. package/dist/lib/neutral/chunk-LFSQMLPK.mjs.map +0 -7
  186. package/dist/lib/neutral/chunk-MBPX7RPI.mjs +0 -14
  187. package/dist/lib/neutral/chunk-MBPX7RPI.mjs.map +0 -7
  188. package/dist/lib/neutral/chunk-OYCDRSWB.mjs +0 -624
  189. package/dist/lib/neutral/chunk-OYCDRSWB.mjs.map +0 -7
  190. package/dist/lib/neutral/chunk-SAWKLGJU.mjs +0 -28
  191. package/dist/lib/neutral/chunk-SAWKLGJU.mjs.map +0 -7
  192. package/dist/lib/neutral/chunk-XCNCK47N.mjs +0 -15
  193. package/dist/lib/neutral/chunk-XCNCK47N.mjs.map +0 -7
  194. package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs +0 -59
  195. package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs.map +0 -7
  196. package/dist/lib/neutral/components/index.mjs +0 -338
  197. package/dist/lib/neutral/components/index.mjs.map +0 -7
  198. package/dist/lib/neutral/containers/index.mjs +0 -17
  199. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  200. package/dist/lib/neutral/create-object-SYZMRR4H.mjs +0 -98
  201. package/dist/lib/neutral/create-object-SYZMRR4H.mjs.map +0 -7
  202. package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs +0 -184
  203. package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs.map +0 -7
  204. package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs +0 -31
  205. package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs.map +0 -7
  206. package/dist/lib/neutral/index.mjs +0 -18
  207. package/dist/lib/neutral/index.mjs.map +0 -7
  208. package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs +0 -65
  209. package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs.map +0 -7
  210. package/dist/lib/neutral/meta.json +0 -1
  211. package/dist/lib/neutral/meta.mjs +0 -8
  212. package/dist/lib/neutral/meta.mjs.map +0 -7
  213. package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs +0 -18
  214. package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs.map +0 -7
  215. package/dist/lib/neutral/operation-handler-JE3743BU.mjs +0 -8
  216. package/dist/lib/neutral/operation-handler-JE3743BU.mjs.map +0 -7
  217. package/dist/lib/neutral/operations/index.mjs +0 -8
  218. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  219. package/dist/lib/neutral/plugin.mjs +0 -16
  220. package/dist/lib/neutral/plugin.mjs.map +0 -7
  221. package/dist/lib/neutral/plugin.workerd.mjs +0 -16
  222. package/dist/lib/neutral/plugin.workerd.mjs.map +0 -7
  223. package/dist/lib/neutral/react-surface-TZESAMG2.mjs +0 -60
  224. package/dist/lib/neutral/react-surface-TZESAMG2.mjs.map +0 -7
  225. package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs +0 -52
  226. package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs.map +0 -7
  227. package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs +0 -8
  228. package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs.map +0 -7
  229. package/dist/lib/neutral/skills/index.mjs.map +0 -7
  230. package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs +0 -99
  231. package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs.map +0 -7
  232. package/dist/lib/neutral/translations.mjs +0 -81
  233. package/dist/lib/neutral/translations.mjs.map +0 -7
  234. package/dist/lib/neutral/types/index.mjs +0 -14
  235. package/dist/lib/neutral/types/index.mjs.map +0 -7
  236. package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
  237. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
  238. package/dist/types/src/operations/curate-magazine.skill.test.d.ts +0 -2
  239. package/dist/types/src/operations/curate-magazine.skill.test.d.ts.map +0 -1
  240. package/src/capabilities/navigation-resolver.ts +0 -21
  241. package/src/operations/curate-magazine.skill.conversations.json +0 -1
  242. package/src/operations/curate-magazine.skill.test.ts +0 -167
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/operations/sources/cors.ts", "../../../src/operations/extraction/article.ts", "../../../src/operations/sources/article.ts", "../../../src/operations/sources/rss.ts", "../../../src/operations/sources/feed-fetcher.ts", "../../../src/operations/sources/http.ts", "../../../src/operations/sources/standard-site.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\n/**\n * Cross-origin fetch helpers. Feed/article URLs are arbitrary third-party origins, so in the browser\n * they must be routed through the dev/edge RSS proxy; server-side (no `window`) they're fetched\n * directly.\n */\n\n/** Browser proxy path; the target URL is appended URL-encoded. */\nexport const CORS_PROXY = '/api/rss?url=';\n\n/** The proxy to use in the current environment: the browser proxy, or undefined server-side. */\nexport const browserCorsProxy = (): string | undefined => (typeof window !== 'undefined' ? CORS_PROXY : undefined);\n\n/** Wraps `url` with `proxy` (URL-encoded) when a proxy is set, else returns `url` unchanged. */\nexport const applyCorsProxy = (url: string, proxy?: string): string =>\n proxy ? `${proxy}${encodeURIComponent(url)}` : url;\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport Defuddle, { type DefuddleResponse } from 'defuddle/full';\n\n/**\n * Article extracted from a web page: main body content (denoised), plus\n * structured metadata and any image URLs found on the page.\n */\nexport type ExtractedArticle = {\n /** Main body text rendered as Markdown. */\n markdown: string;\n /** Cleaned-up article HTML, suitable for rendering directly. */\n html: string;\n /** Article title (from <title>, og:title, schema.org, etc.). */\n title?: string;\n /** Byline / author. */\n author?: string;\n /** Site description / og:description. */\n description?: string;\n /** ISO 8601 published timestamp, when defuddle could find one. */\n published?: string;\n /** Lead image (og:image / twitter:image / first content image). */\n image?: string;\n /** Source domain (e.g. `example.com`). */\n domain?: string;\n /** All image URLs found in the extracted article, lead image first. */\n imageUrls: string[];\n /** Word count of the extracted body. */\n wordCount?: number;\n};\n\nconst isDocumentParserAvailable = (): boolean => typeof DOMParser !== 'undefined';\n\nconst collectImageUrls = (lead: string | undefined, contentHtml: string): string[] => {\n const seen = new Set<string>();\n const urls: string[] = [];\n const push = (url: string | undefined) => {\n if (!url || url.startsWith('data:') || seen.has(url)) {\n return;\n }\n seen.add(url);\n urls.push(url);\n };\n push(lead);\n const imgRegex = /<img\\b[^>]+src=[\"']([^\"']+)[\"']/gi;\n let match: RegExpExecArray | null;\n while ((match = imgRegex.exec(contentHtml)) != null) {\n push(match[1]);\n }\n return urls;\n};\n\n//\n// Trailing-chrome pruning\n//\n// Defuddle's heuristics already strip nav/header/footer/aside at the page\n// level, but on some sites tag clouds and \"related\" rails live INSIDE the\n// `<article>`/`<main>` container — defuddle keeps them because they're\n// structurally part of the body. We walk trailing children of the content\n// root and drop anything that scores as chrome (tag-href list, link-only\n// list, recognisable class/id, high link density). Only trailing siblings\n// are touched — the same heading text mid-article is left alone.\n//\n\n/** Substring patterns on class/id that mark a block as chrome. */\nconst CHROME_CLASS_PATTERN =\n /(?:^|[\\s_-])(?:tag|topic|related|recirc|footer|sidebar|widget|share|social|comments?|disqus|recommend|more[-_]from|read[-_]next|outbrain|taboola)(?:[\\s_-]|$)/i;\n\n/** Hrefs that point to tag/category/related routes. */\nconst CHROME_HREF_PATTERN = /\\/(?:tags?|topics?|categor(?:y|ies)|authors?|related|recommended)\\//i;\n\nconst isHeading = (el: Element): boolean => /^H[1-6]$/i.test(el.tagName);\n\nconst linkDensity = (el: Element): number => {\n const text = (el.textContent ?? '').trim();\n if (text.length === 0) {\n return 0;\n }\n const linkText = Array.from(el.querySelectorAll('a'))\n .map((anchor) => (anchor.textContent ?? '').trim())\n .join(' ');\n return linkText.length / text.length;\n};\n\n/** A `<ul>` / `<ol>` whose items are essentially a single link each. */\nconst isLinkOnlyList = (el: Element): boolean => {\n if (el.tagName !== 'UL' && el.tagName !== 'OL') {\n return false;\n }\n const items = Array.from(el.children).filter((child) => child.tagName === 'LI');\n if (items.length === 0) {\n return false;\n }\n return items.every((li) => {\n const links = li.querySelectorAll('a');\n if (links.length !== 1) {\n return false;\n }\n const text = (li.textContent ?? '').trim();\n const linkText = (links[0].textContent ?? '').trim();\n // The <li>'s text is essentially just the link text (allow a few stray chars).\n return text.length > 0 && Math.abs(text.length - linkText.length) <= 4;\n });\n};\n\n/** Block where the majority of links point to tag/category/related routes. */\nconst isTagURLBlock = (el: Element): boolean => {\n const links = Array.from(el.querySelectorAll('a[href]'));\n if (links.length < 2) {\n return false;\n }\n const matching = links.filter((anchor) => CHROME_HREF_PATTERN.test(anchor.getAttribute('href') ?? ''));\n return matching.length / links.length > 0.6;\n};\n\n/**\n * True when the element has no body-content descendants. Body content is\n * paragraphs, blockquotes, code/pre, figures, images, and tables — the\n * signal that a block contributes article substance, not chrome. (Lists and\n * raw `<a>` tags don't count: tag clouds and link rails are entirely those.)\n */\nconst hasNoBodyContent = (el: Element): boolean =>\n el.querySelector('p, blockquote, pre, code, figure, img, table') == null;\n\nconst isChromeElement = (el: Element): boolean => {\n // Strong structural signals — fire alone.\n const tag = el.tagName;\n if (tag === 'ASIDE' || tag === 'NAV' || tag === 'FOOTER') {\n return true;\n }\n const role = el.getAttribute('role');\n if (role === 'navigation' || role === 'complementary' || role === 'contentinfo') {\n return true;\n }\n // Link-only list is purely structural and self-contained — safe.\n if (isLinkOnlyList(el)) {\n return true;\n }\n // Tag-href ratio AND class-hint can both fire on a wrapper that *contains*\n // a tag rail nested deep among real article paragraphs (the rail's links\n // skew the container's link counts above threshold). Only treat as chrome\n // when the element has no body-content descendants — i.e. it's structurally\n // a link rail itself, not a body wrapper that happens to nest one.\n if (!hasNoBodyContent(el)) {\n return false;\n }\n if (isTagURLBlock(el)) {\n return true;\n }\n const classNameAndId = `${(el.getAttribute('class') ?? '').toString()} ${el.id ?? ''}`;\n if (CHROME_CLASS_PATTERN.test(classNameAndId)) {\n return true;\n }\n return false;\n};\n\n/**\n * Find the element defuddle is most likely to treat as the main content\n * root, so we prune at the same scope it'll later extract. Mirrors the\n * common selector chain article > main > [role=main] > body.\n */\nconst findContentRoot = (doc: Document): Element | null =>\n doc.querySelector('article') ?? doc.querySelector('main') ?? doc.querySelector('[role=\"main\"]') ?? doc.body;\n\n/**\n * First pass: scan all descendants of the content root and remove elements\n * that look like chrome wherever they appear. An element qualifies when:\n * - its class/id contains a chrome keyword\n * (`tag`, `topic`, `related`, `comments`, `share`, `widget`, `sidebar`,\n * `footer`, `recommend`, etc.), AND\n * - it has no body-content descendants (paragraphs, blockquotes, figures,\n * tables) — i.e. it's a self-contained widget, not an article wrapper\n * that happens to share a keyword.\n * Plus elements that are structurally just a list of links (tag clouds,\n * \"related\" rails) regardless of class.\n *\n * This catches chrome buried alongside body content in real-world layouts\n * (e.g. theregister's `<div class=\"similar_topics\">` and `<div class=\"comments\">`\n * nested as siblings of the article body inside `<div id=\"article-wrapper\">`).\n */\nconst pruneChromeDescendants = (root: Element): void => {\n const candidates = Array.from(root.querySelectorAll('*'));\n for (const el of candidates) {\n // Skip elements already detached because an ancestor was removed.\n if (!root.contains(el)) {\n continue;\n }\n if (isChromeElement(el)) {\n el.remove();\n }\n }\n};\n\n/**\n * Second pass: when the descendant scan removed an element that used to sit\n * at the trailing edge of the article, the heading that titled it is now\n * dangling. Strip it.\n *\n * Naturally-trailing headings on legitimate articles (essays ending with\n * `<h2>Conclusion</h2>`) are preserved because we only fire when the\n * original trailing edge was actually severed.\n */\nconst trimDanglingTrailingHeading = (root: Element): void => {\n let cursor = root.lastElementChild;\n while (cursor && isHeading(cursor) && cursor.nextElementSibling == null) {\n const previous = cursor.previousElementSibling;\n cursor.remove();\n cursor = previous;\n }\n};\n\n/** @internal exported for unit testing the chrome-pruning rules in isolation. */\nexport const pruneTrailingChrome = (doc: Document): void => {\n const root = findContentRoot(doc);\n if (!root) {\n return;\n }\n // Capture the original trailing edge so we can tell after pruning whether\n // any chrome was removed FROM the end (vs only from mid-article).\n const originalLastChild = root.lastElementChild;\n pruneChromeDescendants(root);\n if (originalLastChild && !root.contains(originalLastChild)) {\n trimDanglingTrailingHeading(root);\n }\n};\n\nconst mapResult = (result: DefuddleResponse): ExtractedArticle => {\n const lead = result.image || undefined;\n return {\n markdown: result.contentMarkdown ?? '',\n html: result.content ?? '',\n title: result.title || undefined,\n author: result.author || undefined,\n description: result.description || undefined,\n published: result.published || undefined,\n image: lead,\n domain: result.domain || undefined,\n imageUrls: collectImageUrls(lead, result.content ?? ''),\n wordCount: result.wordCount,\n };\n};\n\n/**\n * Extracts the main article from a web page's HTML using `defuddle`.\n * Discards navigation, comments, ads, and other chrome; returns the body\n * as Markdown plus structured metadata.\n *\n * Works in both browser/worker (uses `DOMParser`) and Node (delegates to\n * `defuddle/node`, which uses linkedom). The Node path is loaded lazily so\n * the linkedom dependency stays out of browser bundles.\n */\nexport const extractArticle = async (html: string, url?: string): Promise<ExtractedArticle> => {\n if (!html) {\n return { markdown: '', html: '', imageUrls: [] };\n }\n if (isDocumentParserAvailable()) {\n const doc = new DOMParser().parseFromString(html, 'text/html');\n pruneTrailingChrome(doc);\n return mapResult(new Defuddle(doc, { url, separateMarkdown: true }).parse());\n }\n // Node path: defuddle/node accepts an HTML string and returns a Promise.\n // Trailing-chrome pruning is currently DOM-based and only runs in the\n // browser path; agent operations using the Node path may see boilerplate\n // bleed-through on sites like theregister.com until linkedom-based pruning\n // is added.\n const { Defuddle: DefuddleNode } = await import('defuddle/node');\n return mapResult(await DefuddleNode(html, url, { separateMarkdown: true }));\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { extractArticle } from '../extraction';\nimport { applyCorsProxy } from './cors';\n\nconst FETCH_TIMEOUT_MS = 10_000;\nconst MAX_RESPONSE_BYTES = 2_000_000;\nconst MAX_RESPONSE_BYTES_HEADER = 5_000_000;\n\n/**\n * Exact-match hostname denylist. Defense-in-depth against trivial SSRF when\n * this runs in a trusted/worker context. Not a substitute for DNS-level\n * egress filtering when available.\n */\nconst BLOCKED_HOSTS = new Set([\n 'localhost',\n '127.0.0.1',\n '0.0.0.0',\n '::1',\n '169.254.169.254', // AWS/GCP/Azure instance metadata endpoint.\n 'metadata.google.internal',\n]);\n\n/** Throws unless `link` is an http(s) URL targeting a non-loopback, non-metadata host. */\nconst validateUrl = (link: string): URL => {\n const url = new URL(link);\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error(`Unsupported protocol: ${url.protocol}`);\n }\n const host = url.hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n if (BLOCKED_HOSTS.has(host)) {\n throw new Error(`Blocked host: ${host}`);\n }\n return url;\n};\n\n/**\n * Read the body with a hard byte cap; prevents unbounded memory use on\n * adversarial responses. Throws if the stream API is unavailable so we never\n * silently bypass the cap.\n */\nconst readCapped = async (response: Response, limit: number): Promise<string> => {\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Response body stream unavailable.');\n }\n const decoder = new TextDecoder('utf-8');\n let received = 0;\n let out = '';\n while (received < limit) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n if (value) {\n received += value.byteLength;\n out += decoder.decode(value, { stream: true });\n }\n }\n try {\n await reader.cancel();\n } catch {\n // Ignore cancel errors.\n }\n return (out + decoder.decode()).slice(0, limit);\n};\n\nexport type FetchArticleResult = {\n /** Plain-text body extracted from the article HTML. */\n text: string;\n /** Image URLs found on the page (og:image first, then <img src=...>). */\n imageUrls: string[];\n};\n\nexport type FetchArticleOptions = {\n /**\n * URL prefix for a server-side fetch proxy used to bypass browser CORS.\n * The target URL is appended (URL-encoded). E.g. `'/api/rss?url='`.\n * When omitted, the article is fetched directly.\n */\n corsProxy?: string;\n};\n\n/**\n * Fetches a post's article page over HTTP and returns extracted plain text\n * plus any image URLs found. Applies protocol validation, a fetch timeout,\n * a Content-Length rejection, and a streamed byte cap.\n *\n * Wraps the original error as `cause` so callers can distinguish\n * AbortError (timeout) from network/fetch failures.\n */\nexport const fetchArticle = async (link: string, options: FetchArticleOptions = {}): Promise<FetchArticleResult> => {\n try {\n const url = validateUrl(link);\n const fetchTarget = applyCorsProxy(url.toString(), options.corsProxy);\n const response = await fetch(fetchTarget, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n redirect: 'follow',\n });\n\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n }\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number(contentLength) > MAX_RESPONSE_BYTES_HEADER) {\n throw new Error(`Response too large: ${contentLength} bytes`);\n }\n\n const html = await readCapped(response, MAX_RESPONSE_BYTES);\n const article = await extractArticle(html, url.toString());\n return {\n text: article.markdown,\n imageUrls: article.imageUrls,\n };\n } catch (error) {\n throw new Error(`Failed to fetch article: ${String(error)}`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as FetchHttpClient from '@effect/platform/FetchHttpClient';\nimport * as Effect from 'effect/Effect';\nimport { XMLParser } from 'fast-xml-parser';\n\nimport { normalizeText } from '@dxos/markdown';\n\nimport { Subscription } from '#types';\n\nimport { decodeEntities } from '../../util/text';\nimport { type FeedFetcher, FeedFetchError, type FetchResult } from './feed-fetcher';\nimport { getText } from './http';\n\n/**\n * Unwrap `<![CDATA[ ... ]]>` sections, returning the inner content.\n * fast-xml-parser returns stopNode'd content (description / summary / content / content:encoded)\n * verbatim, so CDATA-wrapped HTML — which feeds use pervasively — arrives as a literal\n * `<![CDATA[ ... ]]>` string. Strip the wrapper(s) so the inner HTML reaches downstream\n * conversion. A no-op for values that contain no CDATA section.\n */\nconst stripCdata = (value: string): string => value.replace(/<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>/g, '$1');\n\n/**\n * Normalize a fast-xml-parser value to a plain string.\n * fast-xml-parser yields objects like `{'#text': 'foo', '@_type': 'html'}` for\n * elements with attributes, and plain strings/numbers for text-only elements.\n * Returns undefined for nullish values.\n *\n * Entities are decoded explicitly: stopNode'd nodes (description / content /\n * summary / content:encoded) are returned as raw text by fast-xml-parser,\n * skipping its built-in entity decoding and CDATA unwrapping. Decoding and\n * CDATA stripping here keep callers from having to special-case those fields.\n * For non-stopped nodes both are no-ops (the parser has already decoded\n * entities and there is no CDATA wrapper).\n */\nconst text = (value: unknown): string | undefined => {\n if (value == null) {\n return undefined;\n }\n if (typeof value === 'string') {\n return decodeEntities(stripCdata(value));\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (typeof value === 'object') {\n const t = (value as { '#text'?: unknown })['#text'];\n if (typeof t === 'string') {\n return decodeEntities(stripCdata(t));\n }\n if (typeof t === 'number' || typeof t === 'boolean') {\n return String(t);\n }\n }\n\n return undefined;\n};\n\n/**\n * Convert a feed text value to Markdown. Feed description/content/summary fields routinely carry\n * embedded HTML (escaped or raw); normalizeText converts it to Markdown and passes plaintext\n * through unchanged. Returns undefined for nullish values.\n */\nconst markdown = (value: string | undefined): string | undefined => (value != null ? normalizeText(value) : undefined);\n\n/** Fetches and parses an RSS/Atom feed URL into Subscription objects. */\nexport const fetchRss: FeedFetcher = (url, options) =>\n Effect.gen(function* () {\n const xml = yield* getText(url, options?.corsProxy);\n return yield* Effect.try({\n try: () => parseFeed(url, xml),\n catch: (cause) => new FeedFetchError({ message: `Unrecognized feed format: ${url}`, cause }),\n });\n }).pipe(Effect.provide(FetchHttpClient.layer));\n\n/** Parses RSS/Atom XML into a normalized {@link FetchResult}; throws on an unrecognized shape. */\nconst parseFeed = (url: string, xml: string): FetchResult => {\n const parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n // RSS/Atom feeds frequently embed HTML (sometimes un-escaped, without CDATA) in content fields,\n // which can blow past fast-xml-parser's default 100-tag nesting cap.\n maxNestedTags: 10_000,\n // Treat known HTML-bearing fields as opaque text so embedded markup isn't parsed as XML.\n stopNodes: ['*.description', '*.summary', '*.content', '*.content:encoded'],\n });\n\n const parsed = parser.parse(xml);\n const channel = parsed.rss?.channel ?? parsed.feed;\n if (!channel) {\n throw new Error('Unrecognized feed format');\n }\n\n const isAtom = !parsed.rss;\n const feedName = text(channel.title) ?? '';\n const feedDescription = markdown(text(isAtom ? channel.subtitle : channel.description)) ?? '';\n\n const items: any[] = (isAtom ? channel.entry : channel.item) ?? [];\n const itemList = Array.isArray(items) ? items : [items];\n\n const posts = itemList.map((item) => {\n const link = isAtom\n ? ((Array.isArray(item.link)\n ? item.link.find((l: any) => l['@_rel'] === 'alternate')?.['@_href']\n : (item.link?.['@_href'] ?? text(item.link))) ?? '')\n : (text(item.link) ?? '');\n\n const author = isAtom\n ? (text(item.author?.name) ?? text(item.author))\n : (text(item['dc:creator']) ?? text(item.author));\n\n const description = markdown(text(item.description));\n const content = isAtom\n ? (markdown(text(item.summary)) ?? markdown(text(item.content)))\n : markdown(text(item['content:encoded']));\n\n return Subscription.makePost({\n title: text(item.title),\n link,\n description,\n content,\n author,\n published: text(item.pubDate) ?? text(item.published) ?? text(item.updated),\n guid: (isAtom ? text(item.id) : text(item.guid)) ?? link,\n });\n });\n\n const feed = Subscription.makeSubscription({\n name: feedName,\n url,\n description: feedDescription,\n });\n\n return { feed, posts };\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Data from 'effect/Data';\nimport type * as Effect from 'effect/Effect';\n\nimport { type Subscription } from '#types';\n\nexport type FetchOptions = {\n corsProxy?: string;\n};\n\nexport type FetchResult = {\n feed: Subscription.Subscription;\n posts: Subscription.Post[];\n};\n\n/** Failure fetching or decoding a feed (network error, non-2xx response, or malformed body). */\nexport class FeedFetchError extends Data.TaggedError('FeedFetchError')<{\n message: string;\n cause?: unknown;\n}> {}\n\n/** Generic feed fetcher — protocol-specific implementations return normalized Subscription objects. */\nexport type FeedFetcher = (url: string, options?: FetchOptions) => Effect.Effect<FetchResult, FeedFetchError>;\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as HttpClient from '@effect/platform/HttpClient';\nimport * as HttpClientRequest from '@effect/platform/HttpClientRequest';\nimport * as HttpClientResponse from '@effect/platform/HttpClientResponse';\nimport * as Effect from 'effect/Effect';\nimport * as Schedule from 'effect/Schedule';\nimport type * as Schema from 'effect/Schema';\n\nimport { applyCorsProxy } from './cors';\nimport { FeedFetchError } from './feed-fetcher';\n\n// Short, bounded retry so a transient hiccup doesn't fail a fetch, without stalling the form.\nconst retryPolicy = Schedule.exponential('500 millis').pipe(Schedule.compose(Schedule.recurs(2)));\n\n/** GETs a URL (through the optional CORS proxy) and decodes the JSON body against `schema`. */\nexport const getJson = <A, I>(\n schema: Schema.Schema<A, I>,\n url: string,\n proxy?: string,\n): Effect.Effect<A, FeedFetchError, HttpClient.HttpClient> =>\n HttpClientRequest.get(applyCorsProxy(url, proxy)).pipe(\n HttpClient.execute,\n Effect.flatMap(HttpClientResponse.schemaBodyJson(schema)),\n Effect.timeout('10 seconds'),\n Effect.retry(retryPolicy),\n Effect.scoped,\n Effect.mapError((cause) => new FeedFetchError({ message: `Fetch failed: ${url}`, cause })),\n );\n\n/** GETs a URL (through the optional CORS proxy) and returns the response body as text. */\nexport const getText = (url: string, proxy?: string): Effect.Effect<string, FeedFetchError, HttpClient.HttpClient> =>\n HttpClientRequest.get(applyCorsProxy(url, proxy)).pipe(\n HttpClient.execute,\n Effect.flatMap((response) => response.text),\n Effect.timeout('10 seconds'),\n Effect.retry(retryPolicy),\n Effect.scoped,\n Effect.mapError((cause) => new FeedFetchError({ message: `Fetch failed: ${url}`, cause })),\n );\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as FetchHttpClient from '@effect/platform/FetchHttpClient';\nimport * as HttpClient from '@effect/platform/HttpClient';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { Subscription } from '#types';\n\nimport { makeSnippet } from '../../util/text';\nimport { type FeedFetcher, FeedFetchError, type FetchOptions } from './feed-fetcher';\nimport { getJson } from './http';\n\n// Standard.site (`site.standard.*`) is the AT Protocol lexicon for long-form articles. Reading is\n// fully decentralized and auth-free: resolve handle → DID → PDS, then list the actor's public\n// `site.standard.document` records. The same records this repo publishes via\n// `docs/scripts/sync-to-atproto.ts`. Standard.site lexicons aren't in `@atproto/api`, so the\n// response shapes are modelled locally and fetched with the platform `HttpClient` (mirroring the AT\n// Protocol endpoints used by `plugin-bluesky`'s `BlueskyApi.resolvePds`).\n\nconst BSKY_PUBLIC_API = 'https://public.api.bsky.app/xrpc';\nconst PLC_DIRECTORY = 'https://plc.directory';\nconst DOCUMENT_COLLECTION = 'site.standard.document';\nconst MARKDOWN_CONTENT_TYPE = 'site.standard.content.markdown';\n\n/** URL builders for the AT Protocol XRPC endpoints used by this module. */\nconst endpoints = {\n resolveHandle: (handle: string) =>\n `${BSKY_PUBLIC_API}/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(handle)}`,\n getProfile: (actor: string) => `${BSKY_PUBLIC_API}/app.bsky.actor.getProfile?actor=${encodeURIComponent(actor)}`,\n searchActors: (query: string, limit: number) =>\n `${BSKY_PUBLIC_API}/app.bsky.actor.searchActorsTypeahead?q=${encodeURIComponent(query)}&limit=${limit}`,\n plcDoc: (did: string) => `${PLC_DIRECTORY}/${did}`,\n listRecords: (pds: string, did: string, collection: string, limit: number) =>\n `${pds}/xrpc/com.atproto.repo.listRecords?repo=${encodeURIComponent(did)}&collection=${encodeURIComponent(collection)}&limit=${limit}`,\n getRecord: (pds: string, did: string, collection: string, rkey: string) =>\n `${pds}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(did)}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent(rkey)}`,\n};\n\n/** A publication a handle publishes under, keyed by its Standard.site `site` reference. */\nexport type Publication = {\n /** The document `site` reference (`at://…` URI or `https://…` URL); the stable selection key. */\n site: string;\n /** Canonical site URL (e.g. `https://dxos.org`), trailing slash stripped. */\n url?: string;\n /** Publication display name. */\n name?: string;\n};\n\n/**\n * Extracts an atproto handle or DID from a URL or raw identifier.\n * Supports: bare handles (`dxos.org`), `@handle`, `did:plc:…`/`did:web:…`, or a\n * `https://bsky.app/profile/{actor}` URL.\n */\nexport const parseStandardSiteActor = (url: string): string => {\n const match = url.match(/bsky\\.app\\/profile\\/([^/?#]+)/);\n if (match) {\n return match[1];\n }\n // Already a DID or bare handle.\n return url.replace(/^@/, '').trim();\n};\n\n/** Lists the publications a handle publishes under (deduped by `site`), for publication selection. */\nexport const listStandardSitePublications = (\n actorOrUrl: string,\n options?: FetchOptions,\n): Effect.Effect<Publication[], FeedFetchError> =>\n Effect.gen(function* () {\n const proxy = options?.corsProxy;\n const actor = parseStandardSiteActor(actorOrUrl);\n const did = yield* resolveDid(actor, proxy);\n const pds = yield* resolvePds(did, proxy);\n const records = yield* listDocuments(pds, did, proxy);\n const sites = distinct(records.map((record) => record.value.site).filter(isString));\n return yield* Effect.forEach(\n sites,\n (site) => resolvePublication(site, proxy).pipe(Effect.catchAll(() => Effect.succeed({ site }))),\n { concurrency: 'unbounded' },\n );\n }).pipe(Effect.provide(FetchHttpClient.layer));\n\n/** A handle suggestion returned by typeahead search. */\nexport type HandleSuggestion = { handle: string; displayName?: string };\n\n/** Searches atproto handles by prefix (typeahead), for combobox suggestions; empty on blank/failed query. */\nexport const searchStandardSiteHandles = (\n query: string,\n options?: FetchOptions,\n): Effect.Effect<HandleSuggestion[], never> =>\n query.trim().length === 0\n ? Effect.succeed([])\n : getJson(SearchActorsResponse, endpoints.searchActors(query.trim(), 8), options?.corsProxy).pipe(\n Effect.map((response) =>\n (response.actors ?? []).map((actor) => ({ handle: actor.handle, displayName: actor.displayName })),\n ),\n Effect.orElseSucceed((): HandleSuggestion[] => []),\n Effect.provide(FetchHttpClient.layer),\n );\n\n/**\n * Fetches a Standard.site feed. `url` is the publication's `site` reference — either an `at://` URI\n * (DID extracted directly) or an `https://` URL (DID resolved via `/.well-known/atproto-did`). In both\n * cases, all documents in the author's repo filtered to that publication are fetched.\n */\nexport const fetchStandardSite: FeedFetcher = (url, options) =>\n Effect.gen(function* () {\n const proxy = options?.corsProxy;\n const did = yield* resolveDidFromSite(url, proxy);\n const pds = yield* resolvePds(did, proxy);\n\n // List all documents in the author's repo scoped to this publication.\n const allRecords = yield* listDocuments(pds, did, proxy);\n const records = allRecords.filter((record) => record.value.site === url);\n\n // Author profile (best-effort) supplies feed name/icon and per-post author.\n const profile = yield* fetchProfile(did, proxy);\n const authorName = profile?.displayName ?? profile?.handle ?? did;\n\n // Resolve the publication record once to get the canonical URL and name.\n const publication = yield* resolvePublication(url, proxy).pipe(\n Effect.catchAll((): Effect.Effect<Publication> => Effect.succeed({ site: url })),\n );\n\n const posts = records.map((record) => {\n const value = record.value;\n const content = value.content?.$type === MARKDOWN_CONTENT_TYPE ? value.content.text : undefined;\n const description = value.description ?? (value.textContent ? makeSnippet(value.textContent) : undefined);\n\n return Subscription.makePost({\n title: value.title,\n link: joinUrl(publication.url, value.path),\n description,\n content,\n author: authorName,\n published: value.publishedAt,\n // The record's AT-URI is the stable dedup key (see `sync-feed.ts` `postKey`).\n guid: record.uri,\n });\n });\n\n // Newest first so `sync-feed`'s cursor (posts[0]) advances correctly.\n posts.sort((postA, postB) => (postB.published ?? '').localeCompare(postA.published ?? ''));\n\n const feed = Subscription.makeSubscription({\n name: publication.name ?? authorName,\n url,\n description: profile?.description ?? `Standard.site articles from @${profile?.handle ?? did}`,\n iconUrl: profile?.avatar,\n type: 'standard-site',\n });\n\n return { feed, posts };\n }).pipe(Effect.provide(FetchHttpClient.layer));\n\n//\n// Response schemas for the XRPC / Standard.site shapes (public APIs, no auth). Excess fields are ignored.\n//\n\nconst ResolveHandleResponse = Schema.Struct({ did: Schema.optional(Schema.String) });\n\nconst SearchActorsResponse = Schema.Struct({\n actors: Schema.optional(\n Schema.Array(Schema.Struct({ handle: Schema.String, displayName: Schema.optional(Schema.String) })),\n ),\n});\n\nconst DidDocument = Schema.Struct({\n service: Schema.optional(\n Schema.Array(\n Schema.Struct({\n id: Schema.optional(Schema.String),\n type: Schema.optional(Schema.String),\n serviceEndpoint: Schema.optional(Schema.String),\n }),\n ),\n ),\n});\n\nconst Profile = Schema.Struct({\n handle: Schema.optional(Schema.String),\n displayName: Schema.optional(Schema.String),\n avatar: Schema.optional(Schema.String),\n description: Schema.optional(Schema.String),\n});\ntype Profile = Schema.Schema.Type<typeof Profile>;\n\nconst StandardSiteDocument = Schema.Struct({\n site: Schema.optional(Schema.String),\n title: Schema.optional(Schema.String),\n publishedAt: Schema.optional(Schema.String),\n path: Schema.optional(Schema.String),\n description: Schema.optional(Schema.String),\n content: Schema.optional(\n Schema.Struct({\n $type: Schema.optional(Schema.String),\n text: Schema.optional(Schema.String),\n }),\n ),\n textContent: Schema.optional(Schema.String),\n});\n\nconst ListRecordsResponse = Schema.Struct({\n records: Schema.optional(Schema.Array(Schema.Struct({ uri: Schema.String, value: StandardSiteDocument }))),\n cursor: Schema.optional(Schema.String),\n});\ntype DocumentRecord = NonNullable<Schema.Schema.Type<typeof ListRecordsResponse>['records']>[number];\n\nconst PublicationRecord = Schema.Struct({\n value: Schema.optional(Schema.Struct({ url: Schema.optional(Schema.String), name: Schema.optional(Schema.String) })),\n});\n\n//\n// Resolution chain (each step requires an `HttpClient`, provided by the public entrypoints above).\n//\n\n/**\n * Resolves a publication `site` reference to its author's DID:\n * - `at://did:…/…` → DID extracted directly from the URI.\n * - `https://…` → DID fetched from `/.well-known/atproto-did` on that domain.\n */\nconst resolveDidFromSite = (\n site: string,\n proxy?: string,\n): Effect.Effect<string, FeedFetchError, HttpClient.HttpClient> => {\n if (site.startsWith('at://')) {\n const parsed = parseAtUri(site);\n return parsed\n ? Effect.succeed(parsed.did)\n : Effect.fail(new FeedFetchError({ message: `Malformed at:// site reference: ${site}` }));\n }\n if (site.startsWith('https://')) {\n const { hostname } = new URL(site);\n return getJson(\n Schema.Struct({ did: Schema.optional(Schema.String) }),\n `https://${hostname}/.well-known/atproto-did`,\n proxy,\n ).pipe(\n Effect.flatMap((result) =>\n result.did\n ? Effect.succeed(result.did)\n : Effect.fail(new FeedFetchError({ message: `No atproto DID found at ${hostname}/.well-known/atproto-did` })),\n ),\n );\n }\n return Effect.fail(new FeedFetchError({ message: `Cannot resolve DID from site reference: ${site}` }));\n};\n\n/** Resolves a handle to a DID (no-op when already a DID) via the public `resolveHandle` XRPC. */\nconst resolveDid = (actor: string, proxy?: string): Effect.Effect<string, FeedFetchError, HttpClient.HttpClient> =>\n actor.startsWith('did:')\n ? Effect.succeed(actor)\n : getJson(ResolveHandleResponse, endpoints.resolveHandle(actor), proxy).pipe(\n Effect.flatMap((resolved) =>\n resolved.did\n ? Effect.succeed(resolved.did)\n : Effect.fail(new FeedFetchError({ message: `Could not resolve handle to DID: ${actor}` })),\n ),\n );\n\n/**\n * Resolves a DID to its PDS endpoint: `did:plc` via the PLC directory DID-doc, `did:web` via the\n * domain's `/.well-known/did.json`. Mirrors `plugin-bluesky`'s `BlueskyApi.resolvePds` endpoints.\n */\nconst resolvePds = (did: string, proxy?: string): Effect.Effect<string, FeedFetchError, HttpClient.HttpClient> => {\n if (did.startsWith('did:plc:')) {\n return getJson(DidDocument, endpoints.plcDoc(did), proxy).pipe(Effect.flatMap((doc) => extractPds(doc, did)));\n }\n if (did.startsWith('did:web:')) {\n // Per the did:web spec `:` separates host from path segments (each percent-encoded); a bare host\n // resolves to `/.well-known/did.json`, path segments to `/<path>/did.json`.\n const [host, ...segments] = did\n .slice('did:web:'.length)\n .split(':')\n .map((segment) => decodeURIComponent(segment));\n if (!host) {\n return Effect.fail(new FeedFetchError({ message: `Invalid did:web identifier: ${did}` }));\n }\n const path = segments.length > 0 ? `/${segments.join('/')}/did.json` : '/.well-known/did.json';\n return getJson(DidDocument, `https://${host}${path}`, proxy).pipe(Effect.flatMap((doc) => extractPds(doc, did)));\n }\n return Effect.fail(new FeedFetchError({ message: `Unsupported DID method: ${did}` }));\n};\n\nconst extractPds = (\n doc: Schema.Schema.Type<typeof DidDocument>,\n did: string,\n): Effect.Effect<string, FeedFetchError> => {\n const service = doc.service?.find(\n (entry) => entry.id === '#atproto_pds' || entry.type === 'AtprotoPersonalDataServer',\n );\n const endpoint = service?.serviceEndpoint;\n return typeof endpoint === 'string' && endpoint.length > 0\n ? Effect.succeed(endpoint.replace(/\\/$/, ''))\n : Effect.fail(new FeedFetchError({ message: `No PDS endpoint found for DID: ${did}` }));\n};\n\n/** Lists ALL of the actor's `site.standard.document` records by following pagination cursors. */\nconst listDocuments = (\n pds: string,\n did: string,\n proxy?: string,\n): Effect.Effect<readonly DocumentRecord[], FeedFetchError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const all: DocumentRecord[] = [];\n let cursor: string | undefined;\n do {\n const url =\n endpoints.listRecords(pds, did, DOCUMENT_COLLECTION, 100) +\n (cursor ? `&cursor=${encodeURIComponent(cursor)}` : '');\n const page = yield* getJson(ListRecordsResponse, url, proxy);\n all.push(...(page.records ?? []));\n cursor = page.cursor;\n } while (cursor);\n return all;\n });\n\n/** Best-effort author profile lookup (display name / avatar / bio); undefined on any failure. */\nconst fetchProfile = (\n actor: string,\n proxy?: string,\n): Effect.Effect<Profile | undefined, never, HttpClient.HttpClient> =>\n getJson(Profile, endpoints.getProfile(actor), proxy).pipe(Effect.catchAll(() => Effect.succeed(undefined)));\n\n/**\n * Resolves a publication `site` reference to its {@link Publication} metadata:\n * - `https://` → canonical URL directly (no record fetch needed).\n * - `at://` → `getRecord` the publication record for `url`/`name`.\n */\nconst resolvePublication = (\n site: string,\n proxy?: string,\n): Effect.Effect<Publication, FeedFetchError, HttpClient.HttpClient> => {\n if (site.startsWith('http')) {\n return Effect.succeed({ site, url: site.replace(/\\/$/, '') });\n }\n if (site.startsWith('at://')) {\n const parsed = parseAtUri(site);\n if (!parsed) {\n return Effect.succeed({ site });\n }\n return Effect.gen(function* () {\n const pds = yield* resolvePds(parsed.did, proxy);\n const record = yield* getJson(\n PublicationRecord,\n endpoints.getRecord(pds, parsed.did, parsed.collection, parsed.rkey),\n proxy,\n );\n const value = record.value ?? {};\n return { site, url: value.url ? value.url.replace(/\\/$/, '') : undefined, name: value.name };\n });\n }\n return Effect.succeed({ site });\n};\n\n//\n// Pure helpers.\n//\n\n/** Splits an `at://{did}/{collection}/{rkey}` URI into its parts; undefined when malformed. */\nconst parseAtUri = (uri: string): { did: string; collection: string; rkey: string } | undefined => {\n const match = uri.match(/^at:\\/\\/([^/]+)\\/([^/]+)\\/([^/]+)$/);\n return match ? { did: match[1], collection: match[2], rkey: match[3] } : undefined;\n};\n\n/** Joins a publication base URL with a document path into a canonical link. */\nconst joinUrl = (base: string | undefined, path: string | undefined): string | undefined => {\n if (!base) {\n return undefined;\n }\n if (!path) {\n return base;\n }\n return `${base}${path.startsWith('/') ? '' : '/'}${path}`;\n};\n\nconst isString = (value: string | undefined): value is string => typeof value === 'string';\n\nconst distinct = (values: readonly string[]): string[] => [...new Set(values)];\n"],
5
- "mappings": "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",
6
- "names": ["CORS_PROXY", "browserCorsProxy", "window", "undefined", "applyCorsProxy", "url", "proxy", "encodeURIComponent", "Defuddle", "isDocumentParserAvailable", "DOMParser", "collectImageUrls", "lead", "contentHtml", "seen", "Set", "urls", "push", "url", "startsWith", "has", "add", "imgRegex", "match", "exec", "CHROME_CLASS_PATTERN", "CHROME_HREF_PATTERN", "isHeading", "el", "test", "tagName", "isLinkOnlyList", "el", "tagName", "items", "Array", "from", "children", "filter", "child", "length", "every", "li", "links", "querySelectorAll", "text", "textContent", "trim", "linkText", "Math", "abs", "isTagURLBlock", "matching", "anchor", "CHROME_HREF_PATTERN", "test", "getAttribute", "hasNoBodyContent", "querySelector", "isChromeElement", "tag", "role", "classNameAndId", "toString", "id", "CHROME_CLASS_PATTERN", "findContentRoot", "doc", "body", "pruneChromeDescendants", "root", "candidates", "contains", "remove", "trimDanglingTrailingHeading", "cursor", "lastElementChild", "isHeading", "nextElementSibling", "previous", "previousElementSibling", "pruneTrailingChrome", "originalLastChild", "mapResult", "result", "lead", "image", "undefined", "markdown", "contentMarkdown", "html", "content", "title", "author", "description", "published", "domain", "imageUrls", "collectImageUrls", "wordCount", "extractArticle", "url", "isDocumentParserAvailable", "DOMParser", "parseFromString", "Defuddle", "separateMarkdown", "parse", "DefuddleNode", "FETCH_TIMEOUT_MS", "MAX_RESPONSE_BYTES", "MAX_RESPONSE_BYTES_HEADER", "BLOCKED_HOSTS", "Set", "validateUrl", "link", "url", "URL", "protocol", "Error", "host", "hostname", "toLowerCase", "replace", "has", "readCapped", "response", "limit", "reader", "body", "getReader", "decoder", "TextDecoder", "received", "out", "value", "done", "read", "byteLength", "decode", "stream", "cancel", "slice", "fetchArticle", "options", "fetchTarget", "applyCorsProxy", "toString", "corsProxy", "fetch", "signal", "AbortSignal", "timeout", "redirect", "ok", "status", "statusText", "contentLength", "headers", "get", "Number", "html", "article", "extractArticle", "text", "markdown", "imageUrls", "error", "String", "cause", "undefined", "FetchHttpClient", "Effect", "XMLParser", "normalizeText", "Subscription", "Data", "FeedFetchError", "TaggedError", "HttpClient", "HttpClientRequest", "HttpClientResponse", "Effect", "Schedule", "retryPolicy", "exponential", "pipe", "compose", "recurs", "getJson", "schema", "url", "proxy", "get", "applyCorsProxy", "execute", "flatMap", "schemaBodyJson", "timeout", "retry", "scoped", "mapError", "cause", "FeedFetchError", "message", "getText", "response", "text", "stripCdata", "value", "replace", "text", "undefined", "decodeEntities", "String", "t", "markdown", "normalizeText", "fetchRss", "url", "options", "gen", "xml", "getText", "corsProxy", "try", "parseFeed", "catch", "cause", "FeedFetchError", "message", "pipe", "provide", "layer", "parser", "XMLParser", "ignoreAttributes", "attributeNamePrefix", "maxNestedTags", "stopNodes", "parsed", "parse", "channel", "rss", "feed", "Error", "isAtom", "feedName", "title", "feedDescription", "subtitle", "description", "items", "entry", "item", "itemList", "Array", "isArray", "posts", "map", "link", "find", "l", "author", "name", "content", "summary", "Subscription", "makePost", "published", "pubDate", "updated", "guid", "id", "makeSubscription", "FetchHttpClient", "Effect", "Schema", "Subscription", "BSKY_PUBLIC_API", "PLC_DIRECTORY", "DOCUMENT_COLLECTION", "MARKDOWN_CONTENT_TYPE", "endpoints", "resolveHandle", "handle", "encodeURIComponent", "getProfile", "actor", "searchActors", "query", "limit", "plcDoc", "did", "listRecords", "pds", "collection", "getRecord", "rkey", "parseStandardSiteActor", "url", "match", "replace", "trim", "listStandardSitePublications", "actorOrUrl", "options", "gen", "proxy", "corsProxy", "resolveDid", "resolvePds", "records", "listDocuments", "sites", "distinct", "map", "record", "value", "site", "filter", "isString", "forEach", "resolvePublication", "pipe", "catchAll", "succeed", "concurrency", "provide", "layer", "searchStandardSiteHandles", "length", "getJson", "SearchActorsResponse", "response", "actors", "displayName", "orElseSucceed", "fetchStandardSite", "resolveDidFromSite", "allRecords", "profile", "fetchProfile", "authorName", "publication", "posts", "content", "$type", "text", "undefined", "description", "textContent", "makeSnippet", "Subscription", "makePost", "title", "link", "joinUrl", "path", "author", "published", "publishedAt", "guid", "uri", "sort", "postA", "postB", "localeCompare", "feed", "makeSubscription", "name", "iconUrl", "avatar", "type", "ResolveHandleResponse", "Struct", "optional", "String", "Array", "DidDocument", "service", "id", "serviceEndpoint", "Profile", "StandardSiteDocument", "ListRecordsResponse", "cursor", "PublicationRecord", "startsWith", "parsed", "parseAtUri", "fail", "FeedFetchError", "message", "hostname", "URL", "flatMap", "result", "resolved", "doc", "extractPds", "host", "segments", "slice", "split", "segment", "decodeURIComponent", "join", "find", "entry", "endpoint", "all", "page", "push", "base", "values", "Set"]
7
- }
@@ -1,57 +0,0 @@
1
- // src/util/text.ts
2
- var DEFAULT_SNIPPET_LENGTH = 280;
3
- var decodeEntities = (input) => input.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => {
4
- const cp = Number.parseInt(hex, 16);
5
- return Number.isFinite(cp) ? String.fromCodePoint(cp) : "";
6
- }).replace(/&#(\d+);/g, (_, dec) => {
7
- const cp = Number.parseInt(dec, 10);
8
- return Number.isFinite(cp) ? String.fromCodePoint(cp) : "";
9
- }).replace(/&nbsp;/gi, " ").replace(/&amp;/gi, "&").replace(/&quot;/gi, '"').replace(/&apos;/gi, "'").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">");
10
- var stripHtml = (html) => {
11
- if (!html) {
12
- return "";
13
- }
14
- const decoded = decodeEntities(html);
15
- const withoutScripts = decoded.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, " ").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, " ");
16
- const withParagraphBreaks = withoutScripts.replace(/<\s*br\s*\/?\s*>/gi, "\n").replace(/<\/\s*(?:p|div|section|article|header|footer|aside|h[1-6]|li|ul|ol|blockquote|pre|tr)\s*>/gi, "\n\n");
17
- const withoutTags = withParagraphBreaks.replace(/<[^>]+>/g, "");
18
- return withoutTags.replace(/[\t\f\v ]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{3,}/g, "\n\n").trim();
19
- };
20
- var makeSnippet = (text, length = DEFAULT_SNIPPET_LENGTH) => {
21
- if (!text) {
22
- return "";
23
- }
24
- if (text.length <= length) {
25
- return text;
26
- }
27
- const clipped = text.slice(0, length);
28
- const lastSpace = clipped.lastIndexOf(" ");
29
- const base = lastSpace > length * 0.6 ? clipped.slice(0, lastSpace) : clipped;
30
- return `${base.trimEnd()}\u2026`;
31
- };
32
- var extractImageUrls = (html) => {
33
- if (!html) {
34
- return [];
35
- }
36
- const urls = [];
37
- const ogMatch = html.match(/<meta[^>]+property=["']og:image["'][^>]+content=["']([^"']+)["']/i) ?? html.match(/<meta[^>]+content=["']([^"']+)["'][^>]+property=["']og:image["']/i);
38
- if (ogMatch?.[1]) {
39
- urls.push(ogMatch[1]);
40
- }
41
- const imgRegex = /<img[^>]+src=["']([^"']+)["']/gi;
42
- let match;
43
- while ((match = imgRegex.exec(html)) != null) {
44
- if (match[1] && !urls.includes(match[1])) {
45
- urls.push(match[1]);
46
- }
47
- }
48
- return urls;
49
- };
50
-
51
- export {
52
- decodeEntities,
53
- stripHtml,
54
- makeSnippet,
55
- extractImageUrls
56
- };
57
- //# sourceMappingURL=chunk-APQRTYT3.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/util/text.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\n/**\n * Lightweight HTML helpers used by the Magazine curation flow.\n * Regex-based; deliberately avoids a parser dependency. Good enough for\n * snippet preview and image discovery; not a content extractor.\n */\n\nconst DEFAULT_SNIPPET_LENGTH = 280;\n\n/** Decode numeric (decimal + hex) and a handful of common named HTML entities. */\nexport const decodeEntities = (input: string): string =>\n input\n .replace(/&#x([0-9a-fA-F]+);/g, (_, hex: string) => {\n const cp = Number.parseInt(hex, 16);\n return Number.isFinite(cp) ? String.fromCodePoint(cp) : '';\n })\n .replace(/&#(\\d+);/g, (_, dec: string) => {\n const cp = Number.parseInt(dec, 10);\n return Number.isFinite(cp) ? String.fromCodePoint(cp) : '';\n })\n .replace(/&nbsp;/gi, ' ')\n .replace(/&amp;/gi, '&')\n .replace(/&quot;/gi, '\"')\n .replace(/&apos;/gi, \"'\")\n .replace(/&lt;/gi, '<')\n .replace(/&gt;/gi, '>');\n\n/**\n * Strip HTML tags and decode common entities to produce plain text.\n * Block-level tag boundaries (paragraphs, divs, headings, list items, line breaks)\n * are converted to newlines so paragraph structure survives the stripping.\n *\n * Decodes entities up front so entity-encoded HTML (`&lt;p&gt;...&lt;/p&gt;` — common in\n * RSS `<description>` payloads, especially under fast-xml-parser stopNodes) gets stripped\n * the same as raw HTML. Without that, the encoded tags would survive stripping and only\n * decode at the end, leaking literal `<p>` into the output.\n */\nexport const stripHtml = (html: string): string => {\n if (!html) {\n return '';\n }\n\n const decoded = decodeEntities(html);\n // Remove script/style blocks entirely.\n const withoutScripts = decoded\n .replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, ' ')\n .replace(/<style\\b[^<]*(?:(?!<\\/style>)<[^<]*)*<\\/style>/gi, ' ');\n // Insert paragraph breaks at common block-level boundaries before stripping tags.\n const withParagraphBreaks = withoutScripts\n .replace(/<\\s*br\\s*\\/?\\s*>/gi, '\\n')\n .replace(/<\\/\\s*(?:p|div|section|article|header|footer|aside|h[1-6]|li|ul|ol|blockquote|pre|tr)\\s*>/gi, '\\n\\n');\n const withoutTags = withParagraphBreaks.replace(/<[^>]+>/g, '');\n return withoutTags\n .replace(/[\\t\\f\\v ]+/g, ' ') // Collapse horizontal whitespace, preserve newlines.\n .replace(/ *\\n */g, '\\n') // Trim spaces around newlines.\n .replace(/\\n{3,}/g, '\\n\\n') // Collapse 3+ blank lines to a single blank line.\n .trim();\n};\n\n/** Produce a snippet of approximately `length` characters, cut on a word boundary. */\nexport const makeSnippet = (text: string, length: number = DEFAULT_SNIPPET_LENGTH): string => {\n if (!text) {\n return '';\n }\n if (text.length <= length) {\n return text;\n }\n const clipped = text.slice(0, length);\n const lastSpace = clipped.lastIndexOf(' ');\n const base = lastSpace > length * 0.6 ? clipped.slice(0, lastSpace) : clipped;\n return `${base.trimEnd()}…`;\n};\n\n/** Extract image URLs from HTML. og:image (meta property) first, then <img src=\"...\">. */\nexport const extractImageUrls = (html: string): string[] => {\n if (!html) {\n return [];\n }\n const urls: string[] = [];\n // Attributes may appear in either order on <meta>, so try both.\n const ogMatch =\n html.match(/<meta[^>]+property=[\"']og:image[\"'][^>]+content=[\"']([^\"']+)[\"']/i) ??\n html.match(/<meta[^>]+content=[\"']([^\"']+)[\"'][^>]+property=[\"']og:image[\"']/i);\n if (ogMatch?.[1]) {\n urls.push(ogMatch[1]);\n }\n const imgRegex = /<img[^>]+src=[\"']([^\"']+)[\"']/gi;\n let match: RegExpExecArray | null;\n while ((match = imgRegex.exec(html)) != null) {\n if (match[1] && !urls.includes(match[1])) {\n urls.push(match[1]);\n }\n }\n return urls;\n};\n"],
5
- "mappings": ";AAUA,IAAMA,yBAAyB;AAGxB,IAAMC,iBAAiB,CAACC,UAC7BA,MACGC,QAAQ,uBAAuB,CAACC,GAAGC,QAAAA;AAClC,QAAMC,KAAKC,OAAOC,SAASH,KAAK,EAAA;AAChC,SAAOE,OAAOE,SAASH,EAAAA,IAAMI,OAAOC,cAAcL,EAAAA,IAAM;AAC1D,CAAA,EACCH,QAAQ,aAAa,CAACC,GAAGQ,QAAAA;AACxB,QAAMN,KAAKC,OAAOC,SAASI,KAAK,EAAA;AAChC,SAAOL,OAAOE,SAASH,EAAAA,IAAMI,OAAOC,cAAcL,EAAAA,IAAM;AAC1D,CAAA,EACCH,QAAQ,YAAY,GAAA,EACpBA,QAAQ,WAAW,GAAA,EACnBA,QAAQ,YAAY,GAAA,EACpBA,QAAQ,YAAY,GAAA,EACpBA,QAAQ,UAAU,GAAA,EAClBA,QAAQ,UAAU,GAAA;AAYhB,IAAMU,YAAY,CAACC,SAAAA;AACxB,MAAI,CAACA,MAAM;AACT,WAAO;EACT;AAEA,QAAMC,UAAUd,eAAea,IAAAA;AAE/B,QAAME,iBAAiBD,QACpBZ,QAAQ,uDAAuD,GAAA,EAC/DA,QAAQ,oDAAoD,GAAA;AAE/D,QAAMc,sBAAsBD,eACzBb,QAAQ,sBAAsB,IAAA,EAC9BA,QAAQ,+FAA+F,MAAA;AAC1G,QAAMe,cAAcD,oBAAoBd,QAAQ,YAAY,EAAA;AAC5D,SAAOe,YACJf,QAAQ,eAAe,GAAA,EACvBA,QAAQ,WAAW,IAAA,EACnBA,QAAQ,WAAW,MAAA,EACnBgB,KAAI;AACT;AAGO,IAAMC,cAAc,CAACC,MAAcC,SAAiBtB,2BAAsB;AAC/E,MAAI,CAACqB,MAAM;AACT,WAAO;EACT;AACA,MAAIA,KAAKC,UAAUA,QAAQ;AACzB,WAAOD;EACT;AACA,QAAME,UAAUF,KAAKG,MAAM,GAAGF,MAAAA;AAC9B,QAAMG,YAAYF,QAAQG,YAAY,GAAA;AACtC,QAAMC,OAAOF,YAAYH,SAAS,MAAMC,QAAQC,MAAM,GAAGC,SAAAA,IAAaF;AACtE,SAAO,GAAGI,KAAKC,QAAO,CAAA;AACxB;AAGO,IAAMC,mBAAmB,CAACf,SAAAA;AAC/B,MAAI,CAACA,MAAM;AACT,WAAO,CAAA;EACT;AACA,QAAMgB,OAAiB,CAAA;AAEvB,QAAMC,UACJjB,KAAKkB,MAAM,mEAAA,KACXlB,KAAKkB,MAAM,mEAAA;AACb,MAAID,UAAU,CAAA,GAAI;AAChBD,SAAKG,KAAKF,QAAQ,CAAA,CAAE;EACtB;AACA,QAAMG,WAAW;AACjB,MAAIF;AACJ,UAAQA,QAAQE,SAASC,KAAKrB,IAAAA,MAAU,MAAM;AAC5C,QAAIkB,MAAM,CAAA,KAAM,CAACF,KAAKM,SAASJ,MAAM,CAAA,CAAE,GAAG;AACxCF,WAAKG,KAAKD,MAAM,CAAA,CAAE;IACpB;EACF;AACA,SAAOF;AACT;",
6
- "names": ["DEFAULT_SNIPPET_LENGTH", "decodeEntities", "input", "replace", "_", "hex", "cp", "Number", "parseInt", "isFinite", "String", "fromCodePoint", "dec", "stripHtml", "html", "decoded", "withoutScripts", "withParagraphBreaks", "withoutTags", "trim", "makeSnippet", "text", "length", "clipped", "slice", "lastSpace", "lastIndexOf", "base", "trimEnd", "extractImageUrls", "urls", "ogMatch", "match", "push", "imgRegex", "exec", "includes"]
7
- }
@@ -1,11 +0,0 @@
1
- // src/paths.ts
2
- import { Paths } from "@dxos/app-toolkit";
3
- import { Magazine } from "#types";
4
- var { getSectionPath: getMagazinesPath, getObjectPath: getMagazinePath } = Paths.createTypeSectionPaths(Magazine.Magazine, {
5
- groupId: Paths.GroupSegments.content
6
- });
7
-
8
- export {
9
- getMagazinesPath
10
- };
11
- //# sourceMappingURL=chunk-GU725ZF4.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/paths.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Paths } from '@dxos/app-toolkit';\n\nimport { Magazine } from '#types';\n\nconst { getSectionPath: getMagazinesPath, getObjectPath: getMagazinePath } = Paths.createTypeSectionPaths(\n Magazine.Magazine,\n { groupId: Paths.GroupSegments.content },\n);\n\nexport { getMagazinePath, getMagazinesPath };\n"],
5
- "mappings": ";AAIA,SAASA,aAAa;AAEtB,SAASC,gBAAgB;AAEzB,IAAM,EAAEC,gBAAgBC,kBAAkBC,eAAeC,gBAAe,IAAKL,MAAMM,uBACjFL,SAASA,UACT;EAAEM,SAASP,MAAMQ,cAAcC;AAAQ,CAAA;",
6
- "names": ["Paths", "Magazine", "getSectionPath", "getMagazinesPath", "getObjectPath", "getMagazinePath", "createTypeSectionPaths", "groupId", "GroupSegments", "content"]
7
- }
@@ -1,10 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- export {
8
- __export
9
- };
10
- //# sourceMappingURL=chunk-J5LGTIGS.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts", "../../../dx.config.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport config from '../dx.config';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.magazine',\n name: 'Magazine',\n author: 'DXOS',\n description: trim`\n MagazinePlugin brings syndicated content into DXOS Composer by syncing RSS feeds\n and ATproto (Bluesky) feeds as ECHO objects stored in the user's space.\n Subscribed feeds are polled incrementally using a cursor so only new posts\n are fetched on each sync, and feed metadata (name, icon, description) is\n persisted alongside the posts for offline access.\n\n Magazines are agent-curated collections drawn from one or more feeds. Each\n Magazine carries the user's topic instructions describing what it should\n cover; pressing the Curate button (or a scheduled trigger) syncs all\n referenced feeds in parallel, then runs a single-shot agent pass that selects\n matching posts and returns their ids, which the operation adds mechanically.\n The agent's base methodology — how to select, how to dedup, and the structured\n output contract — lives in the MagazineSkill. Each magazine stores a\n persisted curation Routine (created at magazine creation time) whose instructions\n hold the editorial brief; pressing Curate runs that Routine against the synced\n candidates via RunInstructions. The skill also exposes a FetchArticleContent\n tool the agent may call to read a candidate's full text when title and\n description are insufficient to judge.\n A short snippet and hero image are derived mechanically from each post for\n display. A Masonry grid renders the curated tiles with images, titles, author\n metadata, and read-state dimming.\n\n Clicking a tile opens the PostArticle detail surface via the deck's layout\n dispatch, routing to the appropriate location (complementary drawer, sibling\n plank, or deck companion) based on the current layout mode. The schema also\n scaffolds a future tagging feature — posts carry an optional tags array and\n the tile renders a tag row when tags are present — enabling navigation and\n feed-discovery flows in a later revision.\n `,\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-magazine',\n icon: { key: 'ph--book-open-text--regular', hue: 'orange' },\n spec: 'PLUGIN.mdl',\n tags: ['labs'],\n },\n});\n"],
5
- "mappings": ";AAIA,SAASA,cAAc;;;ACAvB,SAASC,eAAe;AACxB,SAASC,YAAY;AAErB,IAAA,oBAAeD,QAAQE,KAAK;EAC1BC,QAAQ;IACNC,KAAK;IACLC,MAAM;IACNC,QAAQ;IACRC,aAAaN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8BbO,QAAQ;IACRC,MAAM;MAAEL,KAAK;MAA+BM,KAAK;IAAS;IAC1DC,MAAM;IACNC,MAAM;MAAC;;EACT;AACF,CAAA;;;ADvCO,IAAMC,OAAOC,OAAOC,kBAAkBC,iBAAAA;",
6
- "names": ["Plugin", "Config2", "trim", "make", "plugin", "key", "name", "author", "description", "source", "icon", "hue", "spec", "tags", "meta", "Plugin", "getMetaFromConfig", "config"]
7
- }
@@ -1,36 +0,0 @@
1
- import {
2
- operation_handler_default
3
- } from "./chunk-3K4AQKBZ.mjs";
4
- import {
5
- skill_definition_default
6
- } from "./chunk-MBPX7RPI.mjs";
7
-
8
- // src/MagazinePlugin.workerd.ts
9
- import { Plugin } from "@dxos/app-framework";
10
- import { AppPlugin } from "@dxos/app-toolkit";
11
- import { StateMap, TagIndex } from "@dxos/schema";
12
- import { meta } from "#meta";
13
- import { Magazine, Subscription } from "#types";
14
- var MagazinePlugin = Plugin.define(meta).pipe(AppPlugin.addSkillDefinitionModule({
15
- id: "skill-definition",
16
- activate: skill_definition_default
17
- }), AppPlugin.addOperationHandlerModule({
18
- id: "operation-handler",
19
- activate: operation_handler_default
20
- }), AppPlugin.addSchemaModule({
21
- schema: [
22
- Subscription.Subscription,
23
- Subscription.Post,
24
- Subscription.PostContent,
25
- Magazine.Magazine,
26
- StateMap.StateMap,
27
- TagIndex.TagIndex
28
- ]
29
- }), Plugin.make);
30
- var MagazinePlugin_workerd_default = MagazinePlugin;
31
-
32
- export {
33
- MagazinePlugin,
34
- MagazinePlugin_workerd_default
35
- };
36
- //# sourceMappingURL=chunk-KTYLUOUG.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/MagazinePlugin.workerd.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\nimport { StateMap, TagIndex } from '@dxos/schema';\n\nimport { meta } from '#meta';\nimport { Magazine, Subscription } from '#types';\n\nimport OperationHandler from './capabilities/operation-handler';\nimport SkillDefinition from './capabilities/skill-definition';\n\nexport const MagazinePlugin = Plugin.define(meta).pipe(\n AppPlugin.addSkillDefinitionModule({ id: 'skill-definition', activate: SkillDefinition }),\n AppPlugin.addOperationHandlerModule({ id: 'operation-handler', activate: OperationHandler }),\n AppPlugin.addSchemaModule({\n schema: [\n Subscription.Subscription,\n Subscription.Post,\n Subscription.PostContent,\n Magazine.Magazine,\n StateMap.StateMap,\n TagIndex.TagIndex,\n ],\n }),\n Plugin.make,\n);\n\nexport default MagazinePlugin;\n"],
5
- "mappings": ";;;;;;;;AAIA,SAASA,cAAc;AACvB,SAASC,iBAAiB;AAC1B,SAASC,UAAUC,gBAAgB;AAEnC,SAASC,YAAY;AACrB,SAASC,UAAUC,oBAAoB;AAKhC,IAAMC,iBAAiBC,OAAOC,OAAOC,IAAAA,EAAMC,KAChDC,UAAUC,yBAAyB;EAAEC,IAAI;EAAoBC,UAAUC;AAAgB,CAAA,GACvFJ,UAAUK,0BAA0B;EAAEH,IAAI;EAAqBC,UAAUG;AAAiB,CAAA,GAC1FN,UAAUO,gBAAgB;EACxBC,QAAQ;IACNC,aAAaA;IACbA,aAAaC;IACbD,aAAaE;IACbC,SAASA;IACTC,SAASA;IACTC,SAASA;;AAEb,CAAA,GACAlB,OAAOmB,IAAI;AAGb,IAAA,iCAAepB;",
6
- "names": ["Plugin", "AppPlugin", "StateMap", "TagIndex", "meta", "Magazine", "Subscription", "MagazinePlugin", "Plugin", "define", "meta", "pipe", "AppPlugin", "addSkillDefinitionModule", "id", "activate", "SkillDefinition", "addOperationHandlerModule", "OperationHandler", "addSchemaModule", "schema", "Subscription", "Post", "PostContent", "Magazine", "StateMap", "TagIndex", "make"]
7
- }
@@ -1,8 +0,0 @@
1
- // src/operations/index.ts
2
- import { OperationHandlerSet } from "@dxos/compute";
3
- var MagazineOperationHandlerSet = OperationHandlerSet.lazy(() => import("./clear-magazine-KNY4OWY4.mjs"), () => import("./curate-magazine-7RMKSJC5.mjs"), () => import("./fetch-article-content-CXPKXIMR.mjs"), () => import("./load-post-content-H3S4TKVM.mjs"), () => import("./sync-feed-SDXYF7HU.mjs"));
4
-
5
- export {
6
- MagazineOperationHandlerSet
7
- };
8
- //# sourceMappingURL=chunk-LFSQMLPK.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/operations/index.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { OperationHandlerSet } from '@dxos/compute';\n\nexport const MagazineOperationHandlerSet = OperationHandlerSet.lazy(\n () => import('./clear-magazine'),\n () => import('./curate-magazine'),\n () => import('./fetch-article-content'),\n () => import('./load-post-content'),\n () => import('./sync-feed'),\n);\n"],
5
- "mappings": ";AAIA,SAASA,2BAA2B;AAE7B,IAAMC,8BAA8BD,oBAAoBE,KAC7D,MAAM,OAAO,+BAAA,GACb,MAAM,OAAO,gCAAA,GACb,MAAM,OAAO,sCAAA,GACb,MAAM,OAAO,kCAAA,GACb,MAAM,OAAO,0BAAA,CAAA;",
6
- "names": ["OperationHandlerSet", "MagazineOperationHandlerSet", "lazy"]
7
- }
@@ -1,14 +0,0 @@
1
- // src/capabilities/skill-definition.ts
2
- import * as Effect from "effect/Effect";
3
- import { Capability } from "@dxos/app-framework";
4
- import { AppCapabilities } from "@dxos/app-toolkit";
5
- import { MagazineSkill } from "#skills";
6
- var skillDefinition = () => Effect.succeed([
7
- Capability.contributes(AppCapabilities.SkillDefinition, MagazineSkill)
8
- ]);
9
- var skill_definition_default = skillDefinition;
10
-
11
- export {
12
- skill_definition_default
13
- };
14
- //# sourceMappingURL=chunk-MBPX7RPI.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/skill-definition.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability } from '@dxos/app-framework';\nimport { AppCapabilities } from '@dxos/app-toolkit';\n\nimport { MagazineSkill } from '#skills';\n\nconst skillDefinition = () => Effect.succeed([Capability.contributes(AppCapabilities.SkillDefinition, MagazineSkill)]);\n\nexport default skillDefinition;\n"],
5
- "mappings": ";AAIA,YAAYA,YAAY;AAExB,SAASC,kBAAkB;AAC3B,SAASC,uBAAuB;AAEhC,SAASC,qBAAqB;AAE9B,IAAMC,kBAAkB,MAAaC,eAAQ;EAACJ,WAAWK,YAAYJ,gBAAgBK,iBAAiBJ,aAAAA;CAAe;AAErH,IAAA,2BAAeC;",
6
- "names": ["Effect", "Capability", "AppCapabilities", "MagazineSkill", "skillDefinition", "succeed", "contributes", "SkillDefinition"]
7
- }