@dxos/plugin-magazine 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/MagazinePlugin.mjs +36 -0
- package/dist/lib/MagazinePlugin.mjs.map +1 -0
- package/dist/lib/MagazinePlugin.workerd.mjs +26 -0
- package/dist/lib/MagazinePlugin.workerd.mjs.map +1 -0
- package/dist/lib/atoms.mjs +175 -0
- package/dist/lib/atoms.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +12 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-FeedArticle.mjs +70 -0
- package/dist/lib/chunk-FeedArticle.mjs.map +1 -0
- package/dist/lib/chunk-FeedProperties.mjs +78 -0
- package/dist/lib/chunk-FeedProperties.mjs.map +1 -0
- package/dist/lib/chunk-MagazineArticle.mjs +267 -0
- package/dist/lib/chunk-MagazineArticle.mjs.map +1 -0
- package/dist/lib/chunk-PostArticle.mjs +174 -0
- package/dist/lib/chunk-PostArticle.mjs.map +1 -0
- package/dist/lib/chunk-PostCard.mjs +62 -0
- package/dist/lib/chunk-PostCard.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +91 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-clear-magazine.mjs +37 -0
- package/dist/lib/chunk-clear-magazine.mjs.map +1 -0
- package/dist/lib/chunk-create-object.mjs +59 -0
- package/dist/lib/chunk-create-object.mjs.map +1 -0
- package/dist/lib/chunk-curate-magazine.mjs +164 -0
- package/dist/lib/chunk-curate-magazine.mjs.map +1 -0
- package/dist/lib/chunk-date.mjs +25 -0
- package/dist/lib/chunk-date.mjs.map +1 -0
- package/dist/lib/chunk-fetch-article-content.mjs +26 -0
- package/dist/lib/chunk-fetch-article-content.mjs.map +1 -0
- package/dist/lib/chunk-load-post-content.mjs +57 -0
- package/dist/lib/chunk-load-post-content.mjs.map +1 -0
- package/dist/lib/{neutral/chunk-JFPR6OV4.mjs → chunk-meta.mjs} +19 -26
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +13 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-paths.mjs +8 -0
- package/dist/lib/chunk-paths.mjs.map +1 -0
- package/dist/lib/chunk-post-content.mjs +14 -0
- package/dist/lib/chunk-post-content.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +60 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-routine-templates.mjs +52 -0
- package/dist/lib/chunk-routine-templates.mjs.map +1 -0
- package/dist/lib/chunk-skill-definition.mjs +12 -0
- package/dist/lib/chunk-skill-definition.mjs.map +1 -0
- package/dist/lib/chunk-sources.mjs +576 -0
- package/dist/lib/chunk-sources.mjs.map +1 -0
- package/dist/lib/chunk-sync-feed.mjs +86 -0
- package/dist/lib/chunk-sync-feed.mjs.map +1 -0
- package/dist/lib/chunk-text.mjs +52 -0
- package/dist/lib/chunk-text.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +607 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/components.mjs +323 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +11 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/index.mjs +3 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/operations.mjs +7 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/plugin.workerd.mjs +3 -0
- package/dist/lib/{neutral/skills/index.mjs → skills.mjs} +15 -28
- package/dist/lib/skills.mjs.map +1 -0
- package/dist/lib/testing.mjs +71 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +74 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/MagazinePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/create-object.d.ts +1 -1
- package/dist/types/src/capabilities/index.d.ts +0 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/routine-templates.d.ts +1 -1
- package/dist/types/src/components/PostContent/PostContent.d.ts +1 -13
- package/dist/types/src/components/PostContent/PostContent.d.ts.map +1 -1
- package/dist/types/src/components/PostContent/dedupe-images.d.ts +13 -0
- package/dist/types/src/components/PostContent/dedupe-images.d.ts.map +1 -0
- package/dist/types/src/components/PostContent/index.d.ts +1 -0
- package/dist/types/src/components/PostContent/index.d.ts.map +1 -1
- package/dist/types/src/components/PostStack/PostStack.d.ts +1 -1
- package/dist/types/src/components/PostStack/PostStack.d.ts.map +1 -1
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts +1 -1
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts.map +1 -1
- package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts +4 -1
- package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts.map +1 -1
- package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts +4 -1
- package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts +4 -1
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts +4 -1
- package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts +4 -8
- package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts.map +1 -1
- package/dist/types/src/containers/PostArticle/PostArticle.d.ts +4 -1
- package/dist/types/src/containers/PostArticle/PostArticle.d.ts.map +1 -1
- package/dist/types/src/containers/PostArticle/PostArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/PostArticle/PostToolbar.d.ts +1 -1
- package/dist/types/src/containers/PostArticle/PostToolbar.d.ts.map +1 -1
- package/dist/types/src/containers/PostCard/PostCard.d.ts +4 -6
- package/dist/types/src/containers/PostCard/PostCard.d.ts.map +1 -1
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts +4 -1
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts.map +1 -1
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.d.ts.map +1 -1
- package/dist/types/src/stories/ArticleExtractor.stories.d.ts +1 -0
- package/dist/types/src/stories/ArticleExtractor.stories.d.ts.map +1 -1
- package/dist/types/src/stories/MagazineCurate.stories.d.ts.map +1 -1
- package/dist/types/src/templates/magazine-curation.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -1
- package/package.json +57 -60
- package/src/MagazinePlugin.tsx +0 -3
- package/src/atoms/atoms.test.ts +5 -4
- package/src/capabilities/app-graph-builder.ts +8 -6
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/{react-surface.tsx → react-surface.ts} +10 -12
- package/src/components/PostContent/PostContent.test.ts +1 -1
- package/src/components/PostContent/PostContent.tsx +1 -41
- package/src/components/PostContent/dedupe-images.ts +48 -0
- package/src/components/PostContent/index.ts +1 -0
- package/src/containers/FeedArticle/FeedArticle.stories.tsx +2 -2
- package/src/containers/FeedArticle/FeedArticle.tsx +4 -2
- package/src/containers/FeedProperties/FeedProperties.tsx +6 -4
- package/src/containers/MagazineArticle/MagazineArticle.stories.tsx +2 -1
- package/src/containers/MagazineArticle/MagazineArticle.tsx +8 -6
- package/src/containers/MagazineArticle/MagazineTile.tsx +2 -0
- package/src/containers/MagazineArticle/useToolbar.tsx +2 -0
- package/src/containers/PostArticle/PostArticle.stories.tsx +2 -1
- package/src/containers/PostArticle/PostArticle.tsx +6 -3
- package/src/containers/PostArticle/PostToolbar.tsx +1 -1
- package/src/containers/PostCard/PostCard.tsx +3 -1
- package/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.tsx +2 -1
- package/src/containers/SubscriptionsArticle/SubscriptionsArticle.tsx +5 -3
- package/src/operations/curate-magazine.test.ts +108 -4
- package/src/operations/sync-feed.test.ts +1 -1
- package/src/operations/sync-feed.ts +1 -1
- package/src/paths.ts +3 -3
- package/src/stories/ArticleExtractor.stories.tsx +1 -1
- package/src/stories/MagazineCurate.stories.tsx +3 -2
- package/src/templates/magazine-curation.ts +3 -2
- package/src/types/Magazine.test.ts +1 -1
- package/src/types/Subscription.ts +1 -1
- package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs +0 -90
- package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs.map +0 -7
- package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs +0 -97
- package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs.map +0 -7
- package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs +0 -325
- package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs.map +0 -7
- package/dist/lib/neutral/MagazinePlugin.mjs +0 -62
- package/dist/lib/neutral/MagazinePlugin.mjs.map +0 -7
- package/dist/lib/neutral/MagazinePlugin.workerd.mjs +0 -12
- package/dist/lib/neutral/MagazinePlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs +0 -230
- package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs.map +0 -7
- package/dist/lib/neutral/PostCard-VDGN7BBA.mjs +0 -60
- package/dist/lib/neutral/PostCard-VDGN7BBA.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs +0 -121
- package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -21
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-3K4AQKBZ.mjs +0 -12
- package/dist/lib/neutral/chunk-3K4AQKBZ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-AFPBWBTK.mjs +0 -591
- package/dist/lib/neutral/chunk-AFPBWBTK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-APQRTYT3.mjs +0 -57
- package/dist/lib/neutral/chunk-APQRTYT3.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GU725ZF4.mjs +0 -11
- package/dist/lib/neutral/chunk-GU725ZF4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JFPR6OV4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-KTYLUOUG.mjs +0 -36
- package/dist/lib/neutral/chunk-KTYLUOUG.mjs.map +0 -7
- package/dist/lib/neutral/chunk-LFSQMLPK.mjs +0 -8
- package/dist/lib/neutral/chunk-LFSQMLPK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MBPX7RPI.mjs +0 -14
- package/dist/lib/neutral/chunk-MBPX7RPI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-OYCDRSWB.mjs +0 -624
- package/dist/lib/neutral/chunk-OYCDRSWB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SAWKLGJU.mjs +0 -28
- package/dist/lib/neutral/chunk-SAWKLGJU.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XCNCK47N.mjs +0 -15
- package/dist/lib/neutral/chunk-XCNCK47N.mjs.map +0 -7
- package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs +0 -59
- package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -338
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -17
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/create-object-SYZMRR4H.mjs +0 -98
- package/dist/lib/neutral/create-object-SYZMRR4H.mjs.map +0 -7
- package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs +0 -184
- package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs.map +0 -7
- package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs +0 -31
- package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -18
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs +0 -65
- package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -8
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs +0 -18
- package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs.map +0 -7
- package/dist/lib/neutral/operation-handler-JE3743BU.mjs +0 -8
- package/dist/lib/neutral/operation-handler-JE3743BU.mjs.map +0 -7
- package/dist/lib/neutral/operations/index.mjs +0 -8
- package/dist/lib/neutral/operations/index.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -16
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/plugin.workerd.mjs +0 -16
- package/dist/lib/neutral/plugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-TZESAMG2.mjs +0 -60
- package/dist/lib/neutral/react-surface-TZESAMG2.mjs.map +0 -7
- package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs +0 -52
- package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs.map +0 -7
- package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs +0 -8
- package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs.map +0 -7
- package/dist/lib/neutral/skills/index.mjs.map +0 -7
- package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs +0 -99
- package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -81
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -14
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
- package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
- package/dist/types/src/operations/curate-magazine.skill.test.d.ts +0 -2
- package/dist/types/src/operations/curate-magazine.skill.test.d.ts.map +0 -1
- package/src/capabilities/navigation-resolver.ts +0 -21
- package/src/operations/curate-magazine.skill.conversations.json +0 -1
- package/src/operations/curate-magazine.skill.test.ts +0 -167
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/components/PostContent/PostContent.tsx", "../../../../src/components/PostStack/PostStack.tsx", "../../../../src/components/SubscriptionStack/SubscriptionStack.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport { ScrollArea } from '@dxos/react-ui';\nimport { composable } from '@dxos/react-ui';\nimport { MarkdownView } from '@dxos/react-ui-markdown';\n\nimport { usePostContentAtom } from '#atoms';\nimport { Subscription } from '#types';\n\nimport { formatDate, getImageUrl } from '../../util';\n\nexport type PostContentProps = {\n /** Post to render. */\n post: Subscription.Post;\n /** Additional metadata, such as feed or source domain, rendered between author and published date. */\n metadata?: string[];\n};\n\n/**\n * Strips images from a markdown string whose URL is already on the\n * `excluded` list, AND drops any image that appears more than once. The\n * hero `post.imageUrl` is added to `excluded` by the caller so the\n * extracted article body doesn't re-render the same image immediately\n * below the hero. Captures both Markdown image syntax (``) and inline HTML `<img>` tags that defuddle sometimes\n * leaves behind.\n */\nexport const dedupeImagesInMarkdown = (markdown: string, excluded: ReadonlyArray<string | undefined>): string => {\n const seen = new Set<string>();\n for (const url of excluded) {\n if (url) {\n seen.add(url);\n }\n }\n\n // Markdown image: `` or ``.\n const markdownImg = /!\\[[^\\]]*\\]\\(\\s*([^)\\s]+)(?:\\s+\"[^\"]*\")?\\s*\\)/g;\n // HTML image: `<img ... src=\"url\" ...>`.\n const htmlImg = /<img\\b[^>]*\\bsrc=[\"']([^\"']+)[\"'][^>]*>/gi;\n\n const dedupe = (input: string, regex: RegExp): string =>\n input.replace(regex, (match, url) => {\n if (typeof url !== 'string') {\n return match;\n }\n if (seen.has(url)) {\n return '';\n }\n seen.add(url);\n return match;\n });\n\n return dedupe(dedupe(markdown, markdownImg), htmlImg);\n};\n\n/** Returns true if the markdown contains at least one Markdown or inline HTML image. */\nexport const contentHasImage = (markdown: string): boolean =>\n /!\\[[^\\]]*\\]\\(\\s*[^)\\s]+/.test(markdown) || /<img\\b[^>]*\\bsrc=[\"'][^\"']+[\"']/i.test(markdown);\n\n/**\n * Shared presentational layout for an article-style post.\n * Render order: title → hero image → Markdown body (subscription contentFeed\n * entry for this Post id, falling back to `post.description`) → meta line\n * (author · …extra · published).\n */\nexport const PostContent = composable<HTMLDivElement, PostContentProps>(\n ({ post, metadata = [], ...props }, forwardedRef) => {\n const meta = [post.author, ...metadata, formatDate(post.published)].filter(Boolean).join(' · ');\n const title = post.title;\n const postContent = usePostContentAtom(post);\n const imageUrl = getImageUrl(post, postContent);\n const fetchedText = postContent?.text;\n\n // Drop duplicate images from the article body — and remove any image\n // that matches the hero `imageUrl` so it doesn't appear stacked immediately\n // below the hero. Falls through to `post.description` when content\n // hasn't been fetched yet.\n const content = useMemo(() => {\n const source = fetchedText || post.description || '';\n if (!source) {\n return '';\n }\n return dedupeImagesInMarkdown(source, [imageUrl]);\n }, [fetchedText, post.description, imageUrl]);\n\n // Suppress the hero when the article body already carries imagery — RSS feeds often\n // duplicate the lead image inside `<content>` under a different URL than `imageUrl`,\n // and rendering both stacks the same picture twice (see e.g. Guardian galleries).\n const showHero = useMemo(\n () => Boolean(imageUrl?.startsWith('http')) && !contentHasImage(content),\n [imageUrl, content],\n );\n\n return (\n <ScrollArea.Root {...props} orientation='vertical' thin ref={forwardedRef}>\n <ScrollArea.Viewport classNames='flex flex-col gap-3 p-4'>\n {title && <h1 className='text-xl font-semibold'>{title}</h1>}\n {showHero && <img src={imageUrl} alt='' className='rounded w-full object-cover max-h-72' loading='lazy' />}\n {content && <MarkdownView content={content} />}\n {meta && <div className='text-xs text-subdued'>{meta}</div>}\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n );\n },\n);\n\nPostContent.displayName = 'PostContent';\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type KeyboardEvent, forwardRef, useCallback, useMemo, useState } from 'react';\n\nimport { Type } from '@dxos/echo';\nimport { Card, Icon, ScrollArea, useTranslation } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { MarkdownView } from '@dxos/react-ui-markdown';\nimport { Focus, Mosaic, type MosaicTileProps, useMosaicContainer } from '@dxos/react-ui-mosaic';\n\nimport { Subscription } from '#types';\n\nexport type PostStackAction = { type: 'current'; postId: string };\n\nexport type PostStackActionHandler = (action: PostStackAction) => void;\n\nexport type PostStackProps = {\n id: string;\n posts?: Subscription.Post[];\n currentId?: string;\n onAction?: PostStackActionHandler;\n};\n\nexport const PostStack = composable<HTMLDivElement, PostStackProps>(\n ({ posts = [], currentId, onAction, ...props }, forwardedRef) => {\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n const items = useMemo(() => posts.map((post) => ({ post, onAction })), [posts, onAction]);\n\n const handleCurrentChange = useCallback(\n (id: string | undefined) => {\n if (id) {\n onAction?.({ type: 'current', postId: id });\n }\n },\n [onAction],\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n (document.activeElement as HTMLElement | null)?.click();\n }\n }, []);\n\n return (\n <Focus.Group asChild {...composableProps(props)} onKeyDown={handleKeyDown} ref={forwardedRef}>\n <Mosaic.Container\n asChild\n withFocus\n autoScroll={viewport}\n currentId={currentId}\n onCurrentChange={handleCurrentChange}\n >\n <ScrollArea.Root orientation='vertical' padding centered>\n <ScrollArea.Viewport ref={setViewport}>\n <Mosaic.VirtualStack\n Tile={PostTile}\n classNames='my-2'\n gap={8}\n items={items}\n draggable={false}\n getId={(item) => item.post.id}\n getScrollElement={() => viewport}\n estimateSize={() => 120}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n </Focus.Group>\n );\n },\n);\n\nPostStack.displayName = 'PostStack';\n\ntype PostTileData = {\n post: Subscription.Post;\n onAction?: PostStackActionHandler;\n};\n\ntype PostTileProps = Pick<MosaicTileProps<PostTileData>, 'data' | 'location' | 'current'>;\n\nconst PostTile = forwardRef<HTMLDivElement, PostTileProps>(({ data, location, current }, forwardedRef) => {\n const post = data?.post;\n const { setCurrentId } = useMosaicContainer('PostTile');\n const { t } = useTranslation(Type.getTypename(Subscription.Post));\n\n const handleCurrentChange = useCallback(() => {\n if (post) {\n setCurrentId(post.id);\n }\n }, [post, setCurrentId]);\n\n if (!post) {\n return null;\n }\n\n const published = post.published ? new Date(post.published).toLocaleDateString() : undefined;\n\n return (\n <Mosaic.Tile asChild classNames='dx-hover dx-current' id={post.id} data={data} location={location}>\n <Focus.Item asChild current={current} onCurrentChange={handleCurrentChange}>\n <Card.Root ref={forwardedRef} fullWidth>\n <Card.Header>\n <Card.Block>\n <Icon icon='ph--dot-outline--regular' />\n </Card.Block>\n <Card.Text classNames='truncate'>{post.title ?? t('post-title.placeholder')}</Card.Text>\n {post.link && (\n <Card.Block end>\n <a href={post.link} target='_blank' rel='noreferrer' className='shrink-0'>\n <Icon icon='ph--arrow-square-out--regular' size={4} />\n </a>\n </Card.Block>\n )}\n </Card.Header>\n <Card.Body>\n {post.author && (\n <Card.Row>\n <Card.Block>\n <Icon icon='ph--user--regular' />\n </Card.Block>\n <Card.Text variant='description'>{post.author}</Card.Text>\n </Card.Row>\n )}\n {(post.description || post.content) && (\n <Card.Row>\n <MarkdownView\n content={post.description ?? post.content}\n classNames='line-clamp-5 text-sm text-description'\n />\n </Card.Row>\n )}\n {published && (\n <Card.Row>\n <Card.Block>\n <Icon icon='ph--calendar--regular' />\n </Card.Block>\n <Card.Text variant='description'>{published}</Card.Text>\n </Card.Row>\n )}\n </Card.Body>\n </Card.Root>\n </Focus.Item>\n </Mosaic.Tile>\n );\n});\n\nPostTile.displayName = 'PostTile';\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type KeyboardEvent, forwardRef, useCallback, useMemo, useState } from 'react';\n\nimport { Card, Icon, ScrollArea } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { Focus, Mosaic, type MosaicTileProps, useMosaicContainer } from '@dxos/react-ui-mosaic';\n\nimport { type Subscription } from '#types';\n\nexport type SubscriptionStackAction =\n | { type: 'current'; feedId: string }\n | { type: 'sync'; feedId: string }\n | { type: 'delete'; feedId: string };\n\nexport type SubscriptionStackActionHandler = (action: SubscriptionStackAction) => void;\n\n//\n// SubscriptionStack\n//\n\nexport type SubscriptionStackProps = {\n id?: string;\n feeds?: Subscription.Subscription[];\n currentId?: string;\n onAction?: SubscriptionStackActionHandler;\n};\n\nexport const SubscriptionStack = composable<HTMLDivElement, SubscriptionStackProps>(\n ({ feeds = [], currentId, onAction, ...props }, forwardedRef) => {\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n\n // TODO(burdon): Either sort or make draggable.\n const items = useMemo(() => feeds.map((feed) => ({ feed, onAction })), [feeds, onAction]);\n\n const handleCurrentChange = useCallback(\n (id: string | undefined) => {\n if (id) {\n onAction?.({ type: 'current', feedId: id });\n }\n },\n [onAction],\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n (document.activeElement as HTMLElement | null)?.click();\n }\n }, []);\n\n return (\n <Focus.Group asChild {...composableProps(props)} onKeyDown={handleKeyDown} ref={forwardedRef}>\n <Mosaic.Container\n asChild\n withFocus\n autoScroll={viewport}\n currentId={currentId}\n onCurrentChange={handleCurrentChange}\n >\n <ScrollArea.Root orientation='vertical' padding centered>\n <ScrollArea.Viewport ref={setViewport}>\n <Mosaic.VirtualStack\n Tile={SubscriptionTile}\n classNames='my-2'\n gap={8}\n items={items}\n draggable={false}\n getId={(item) => item.feed.id}\n getScrollElement={() => viewport}\n estimateSize={() => 100}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n </Focus.Group>\n );\n },\n);\n\nSubscriptionStack.displayName = 'SubscriptionStack';\n\n//\n// SubscriptionTile\n//\n\nconst icons: Record<Subscription.FeedType, { icon: string; className?: string }> = {\n 'standard-site': {\n icon: 'ph--article--regular',\n className: 'text-sky-500',\n },\n 'rss': {\n icon: 'ph--rss--regular',\n className: 'text-green-500',\n },\n 'bluesky': {\n icon: 'ph--butterfly--regular',\n className: 'text-blue-500',\n },\n};\n\ntype SubscriptionTileData = {\n feed: Subscription.Subscription;\n onAction?: SubscriptionStackActionHandler;\n};\n\ntype SubscriptionTileProps = Pick<MosaicTileProps<SubscriptionTileData>, 'data' | 'location' | 'current'>;\n\nconst SubscriptionTile = forwardRef<HTMLDivElement, SubscriptionTileProps>(\n ({ data, location, current }, forwardedRef) => {\n const { feed, onAction } = data;\n const { setCurrentId } = useMosaicContainer('SubscriptionTile');\n const { icon, className: iconClassName } = icons[feed.type ?? 'rss'] || icons.rss;\n\n const handleCurrentChange = useCallback(() => {\n setCurrentId(feed.id);\n }, [feed.id, setCurrentId]);\n\n const menuItems = useMemo(\n () => [\n { label: 'Sync', onClick: () => onAction?.({ type: 'sync', feedId: feed.id }) },\n { label: 'Delete', onClick: () => onAction?.({ type: 'delete', feedId: feed.id }) },\n ],\n [feed.id, onAction],\n );\n\n return (\n <Mosaic.Tile asChild classNames='dx-hover dx-current' id={feed.id} data={data} location={location}>\n <Focus.Item asChild current={current} onCurrentChange={handleCurrentChange}>\n <Card.Root ref={forwardedRef}>\n <Card.Header>\n <Card.Block>\n <Icon icon={icon} classNames={iconClassName} />\n </Card.Block>\n <Card.Title>{feed.name ?? 'Untitled feed'}</Card.Title>\n <Card.Menu items={menuItems} />\n </Card.Header>\n <Card.Body>\n {/* {feed.url && (\n <Card.Row>\n <Card.Text classNames='truncate' variant='description'>\n {feed.url}\n </Card.Text>\n </Card.Row>\n )} */}\n {feed.description && (\n <Card.Row>\n <Card.Text variant='description'>{feed.description}</Card.Text>\n </Card.Row>\n )}\n </Card.Body>\n </Card.Root>\n </Focus.Item>\n </Mosaic.Tile>\n );\n },\n);\n\nSubscriptionTile.displayName = 'SubscriptionTile';\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["React", "useMemo", "ScrollArea", "composable", "MarkdownView", "usePostContentAtom", "dedupeImagesInMarkdown", "markdown", "excluded", "seen", "Set", "url", "add", "markdownImg", "htmlImg", "dedupe", "input", "regex", "replace", "match", "has", "contentHasImage", "test", "PostContent", "composable", "post", "metadata", "props", "forwardedRef", "meta", "author", "formatDate", "published", "filter", "Boolean", "join", "title", "postContent", "usePostContentAtom", "imageUrl", "getImageUrl", "fetchedText", "text", "content", "useMemo", "source", "description", "showHero", "startsWith", "ScrollArea", "Root", "orientation", "thin", "ref", "Viewport", "classNames", "h1", "className", "img", "src", "alt", "loading", "MarkdownView", "div", "displayName", "React", "forwardRef", "useCallback", "useMemo", "useState", "Type", "Card", "Icon", "ScrollArea", "useTranslation", "composable", "composableProps", "MarkdownView", "Focus", "Mosaic", "useMosaicContainer", "Subscription", "PostStack", "posts", "currentId", "onAction", "props", "forwardedRef", "viewport", "setViewport", "items", "map", "post", "handleCurrentChange", "id", "type", "postId", "handleKeyDown", "event", "key", "preventDefault", "document", "activeElement", "click", "Group", "asChild", "onKeyDown", "ref", "Container", "withFocus", "autoScroll", "onCurrentChange", "Root", "orientation", "padding", "centered", "Viewport", "VirtualStack", "Tile", "PostTile", "classNames", "gap", "draggable", "getId", "item", "getScrollElement", "estimateSize", "displayName", "data", "location", "current", "setCurrentId", "t", "getTypename", "Post", "published", "Date", "toLocaleDateString", "undefined", "Item", "fullWidth", "Header", "Block", "icon", "Text", "title", "link", "end", "a", "href", "target", "rel", "className", "size", "Body", "author", "Row", "variant", "description", "content", "React", "forwardRef", "useCallback", "useMemo", "useState", "Card", "Icon", "ScrollArea", "composable", "composableProps", "Focus", "Mosaic", "useMosaicContainer", "SubscriptionStack", "feeds", "currentId", "onAction", "props", "forwardedRef", "viewport", "setViewport", "items", "map", "feed", "handleCurrentChange", "id", "type", "feedId", "handleKeyDown", "event", "key", "preventDefault", "document", "activeElement", "click", "Group", "asChild", "onKeyDown", "ref", "Container", "withFocus", "autoScroll", "onCurrentChange", "Root", "orientation", "padding", "centered", "Viewport", "VirtualStack", "Tile", "SubscriptionTile", "classNames", "gap", "draggable", "getId", "item", "getScrollElement", "estimateSize", "displayName", "icons", "icon", "className", "data", "location", "current", "setCurrentId", "iconClassName", "rss", "menuItems", "label", "onClick", "Item", "Header", "Block", "Title", "name", "Menu", "Body", "description", "Row", "Text", "variant"]
|
|
7
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import "../chunk-J5LGTIGS.mjs";
|
|
2
|
-
|
|
3
|
-
// src/containers/index.ts
|
|
4
|
-
import { lazy } from "react";
|
|
5
|
-
var FeedArticle = lazy(() => import("../FeedArticle-PEWCFFSP.mjs"));
|
|
6
|
-
var FeedProperties = lazy(() => import("../FeedProperties-EIO7IZOA.mjs"));
|
|
7
|
-
var MagazineArticle = lazy(() => import("../MagazineArticle-5T7RTIPS.mjs"));
|
|
8
|
-
var PostArticle = lazy(() => import("../PostArticle-BGIPU7XA.mjs"));
|
|
9
|
-
var PostCard = lazy(() => import("../PostCard-VDGN7BBA.mjs"));
|
|
10
|
-
export {
|
|
11
|
-
FeedArticle,
|
|
12
|
-
FeedProperties,
|
|
13
|
-
MagazineArticle,
|
|
14
|
-
PostArticle,
|
|
15
|
-
PostCard
|
|
16
|
-
};
|
|
17
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/containers/index.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport const FeedArticle: ComponentType<any> = lazy(() => import('./FeedArticle'));\nexport const FeedProperties: ComponentType<any> = lazy(() => import('./FeedProperties'));\nexport const MagazineArticle: ComponentType<any> = lazy(() => import('./MagazineArticle'));\nexport const PostArticle: ComponentType<any> = lazy(() => import('./PostArticle'));\nexport const PostCard: ComponentType<any> = lazy(() => import('./PostCard'));\n"],
|
|
5
|
-
"mappings": ";;;AAIA,SAA6BA,YAAY;AAElC,IAAMC,cAAkCD,KAAK,MAAM,OAAO,6BAAA,CAAA;AAC1D,IAAME,iBAAqCF,KAAK,MAAM,OAAO,gCAAA,CAAA;AAC7D,IAAMG,kBAAsCH,KAAK,MAAM,OAAO,iCAAA,CAAA;AAC9D,IAAMI,cAAkCJ,KAAK,MAAM,OAAO,6BAAA,CAAA;AAC1D,IAAMK,WAA+BL,KAAK,MAAM,OAAO,0BAAA,CAAA;",
|
|
6
|
-
"names": ["lazy", "FeedArticle", "FeedProperties", "MagazineArticle", "PostArticle", "PostCard"]
|
|
7
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
browserCorsProxy,
|
|
3
|
-
fetchRss,
|
|
4
|
-
listStandardSitePublications,
|
|
5
|
-
searchStandardSiteHandles
|
|
6
|
-
} from "./chunk-AFPBWBTK.mjs";
|
|
7
|
-
import {
|
|
8
|
-
getMagazinesPath
|
|
9
|
-
} from "./chunk-GU725ZF4.mjs";
|
|
10
|
-
import "./chunk-APQRTYT3.mjs";
|
|
11
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
12
|
-
|
|
13
|
-
// src/capabilities/create-object.ts
|
|
14
|
-
import * as Effect from "effect/Effect";
|
|
15
|
-
import * as Schema from "effect/Schema";
|
|
16
|
-
import { Capability } from "@dxos/app-framework";
|
|
17
|
-
import { Operation } from "@dxos/compute";
|
|
18
|
-
import { Obj, Ref, Type } from "@dxos/echo";
|
|
19
|
-
import { SpaceOperation } from "@dxos/plugin-space";
|
|
20
|
-
import { SpaceCapabilities } from "@dxos/plugin-space";
|
|
21
|
-
import { AutofillAnnotation, OptionsLookupAnnotation, autofill, optionsLookup } from "@dxos/react-ui-form";
|
|
22
|
-
import { CreateSubscription, FeedOperation, Magazine, Subscription } from "#types";
|
|
23
|
-
var StandardSiteCreate = Schema.Struct({
|
|
24
|
-
...CreateSubscription.StandardSiteCreateBase.fields,
|
|
25
|
-
// Handle is a combobox: typing queries known handles (typeahead); the typed text stays selectable.
|
|
26
|
-
handle: CreateSubscription.StandardSiteCreateBase.fields.handle.pipe(OptionsLookupAnnotation.set(optionsLookup()([
|
|
27
|
-
"handle"
|
|
28
|
-
], ({ handle }) => searchStandardSiteHandles(handle ?? "", {
|
|
29
|
-
corsProxy: browserCorsProxy()
|
|
30
|
-
}).pipe(Effect.map((suggestions) => suggestions.map((suggestion) => ({
|
|
31
|
-
value: suggestion.handle,
|
|
32
|
-
label: suggestion.handle,
|
|
33
|
-
secondaryLabel: suggestion.displayName
|
|
34
|
-
})))), {
|
|
35
|
-
combobox: true
|
|
36
|
-
}))),
|
|
37
|
-
// Publication options are looked up from the entered `handle`.
|
|
38
|
-
publication: CreateSubscription.StandardSiteCreateBase.fields.publication.pipe(OptionsLookupAnnotation.set(optionsLookup()([
|
|
39
|
-
"handle"
|
|
40
|
-
], ({ handle }) => CreateSubscription.isHandle(handle) ? listStandardSitePublications(handle, {
|
|
41
|
-
corsProxy: browserCorsProxy()
|
|
42
|
-
}).pipe(Effect.map((publications) => publications.map((publication) => ({
|
|
43
|
-
value: publication.site,
|
|
44
|
-
label: publication.name ?? publication.url ?? publication.site
|
|
45
|
-
}))), Effect.orElseSucceed(() => [])) : Effect.succeed([]))))
|
|
46
|
-
});
|
|
47
|
-
var RssCreate = Schema.Struct({
|
|
48
|
-
...CreateSubscription.RssCreateBase.fields,
|
|
49
|
-
// Name is pre-filled from the feed title once the `url` is a valid feed URL.
|
|
50
|
-
name: Schema.optional(Schema.String.pipe(AutofillAnnotation.set(autofill()([
|
|
51
|
-
"url"
|
|
52
|
-
], ({ url }) => CreateSubscription.isUrl(url) ? fetchRss(url, {
|
|
53
|
-
corsProxy: browserCorsProxy()
|
|
54
|
-
}).pipe(Effect.map((result) => result.feed.name), Effect.orElseSucceed(() => void 0)) : Effect.succeed(void 0)))).annotations({
|
|
55
|
-
title: "Name"
|
|
56
|
-
}))
|
|
57
|
-
});
|
|
58
|
-
var CreateSubscriptionSchema = Schema.Union(StandardSiteCreate, RssCreate);
|
|
59
|
-
var create_object_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
60
|
-
return [
|
|
61
|
-
Capability.contributes(SpaceCapabilities.CreateObjectEntry, {
|
|
62
|
-
id: Type.getTypename(Subscription.Subscription),
|
|
63
|
-
inputSchema: CreateSubscriptionSchema,
|
|
64
|
-
createObject: (props, options) => Effect.gen(function* () {
|
|
65
|
-
const object = CreateSubscription.makeSubscriptionFromCreate(props);
|
|
66
|
-
const result = yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
67
|
-
object,
|
|
68
|
-
target: options.target,
|
|
69
|
-
targetNodeId: options.targetNodeId
|
|
70
|
-
});
|
|
71
|
-
if (object.url) {
|
|
72
|
-
yield* Operation.schedule(FeedOperation.SyncFeed, {
|
|
73
|
-
feed: Ref.make(object)
|
|
74
|
-
}, {
|
|
75
|
-
spaceId: Obj.getDatabase(object)?.spaceId
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return result;
|
|
79
|
-
})
|
|
80
|
-
}),
|
|
81
|
-
Capability.contributes(SpaceCapabilities.CreateObjectEntry, {
|
|
82
|
-
id: Type.getTypename(Magazine.Magazine),
|
|
83
|
-
inputSchema: Magazine.CreateMagazineSchema,
|
|
84
|
-
createObject: (props, options) => Effect.gen(function* () {
|
|
85
|
-
const magazine = Magazine.make(props);
|
|
86
|
-
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
87
|
-
object: magazine,
|
|
88
|
-
target: options.target,
|
|
89
|
-
targetNodeId: getMagazinesPath(options.db.spaceId)
|
|
90
|
-
});
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
];
|
|
94
|
-
}));
|
|
95
|
-
export {
|
|
96
|
-
create_object_default as default
|
|
97
|
-
};
|
|
98
|
-
//# sourceMappingURL=create-object-SYZMRR4H.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/capabilities/create-object.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { Capability } from '@dxos/app-framework';\nimport { Operation } from '@dxos/compute';\nimport { Obj, Ref, Type } from '@dxos/echo';\nimport { SpaceOperation } from '@dxos/plugin-space';\nimport { SpaceCapabilities } from '@dxos/plugin-space';\nimport { AutofillAnnotation, OptionsLookupAnnotation, autofill, optionsLookup } from '@dxos/react-ui-form';\n\nimport { CreateSubscription, FeedOperation, Magazine, Subscription } from '#types';\n\nimport {\n browserCorsProxy,\n fetchRss,\n listStandardSitePublications,\n searchStandardSiteHandles,\n} from '../operations/sources';\nimport { getMagazinesPath } from '../paths';\n\nconst StandardSiteCreate = Schema.Struct({\n ...CreateSubscription.StandardSiteCreateBase.fields,\n // Handle is a combobox: typing queries known handles (typeahead); the typed text stays selectable.\n handle: CreateSubscription.StandardSiteCreateBase.fields.handle.pipe(\n OptionsLookupAnnotation.set(\n optionsLookup<CreateSubscription.StandardSiteValues>()(\n ['handle'],\n ({ handle }) =>\n searchStandardSiteHandles(handle ?? '', { corsProxy: browserCorsProxy() }).pipe(\n Effect.map((suggestions) =>\n suggestions.map((suggestion) => ({\n value: suggestion.handle,\n label: suggestion.handle,\n secondaryLabel: suggestion.displayName,\n })),\n ),\n ),\n { combobox: true },\n ),\n ),\n ),\n // Publication options are looked up from the entered `handle`.\n publication: CreateSubscription.StandardSiteCreateBase.fields.publication.pipe(\n OptionsLookupAnnotation.set(\n optionsLookup<CreateSubscription.StandardSiteValues>()(['handle'], ({ handle }) =>\n CreateSubscription.isHandle(handle)\n ? listStandardSitePublications(handle, { corsProxy: browserCorsProxy() }).pipe(\n Effect.map((publications) =>\n publications.map((publication) => ({\n value: publication.site,\n label: publication.name ?? publication.url ?? publication.site,\n })),\n ),\n Effect.orElseSucceed(() => []),\n )\n : Effect.succeed([]),\n ),\n ),\n ),\n});\n\nconst RssCreate = Schema.Struct({\n ...CreateSubscription.RssCreateBase.fields,\n // Name is pre-filled from the feed title once the `url` is a valid feed URL.\n name: Schema.optional(\n Schema.String.pipe(\n AutofillAnnotation.set(\n autofill<CreateSubscription.RssValues>()(['url'], ({ url }) =>\n CreateSubscription.isUrl(url)\n ? fetchRss(url, { corsProxy: browserCorsProxy() }).pipe(\n Effect.map((result) => result.feed.name),\n Effect.orElseSucceed(() => undefined),\n )\n : Effect.succeed(undefined),\n ),\n ),\n ).annotations({ title: 'Name' }),\n ),\n});\n\nconst CreateSubscriptionSchema = Schema.Union(StandardSiteCreate, RssCreate);\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return [\n Capability.contributes(SpaceCapabilities.CreateObjectEntry, {\n id: Type.getTypename(Subscription.Subscription),\n inputSchema: CreateSubscriptionSchema,\n createObject: (props, options) =>\n Effect.gen(function* () {\n const object = CreateSubscription.makeSubscriptionFromCreate(props);\n const result = yield* Operation.invoke(SpaceOperation.AddObject, {\n object,\n target: options.target,\n targetNodeId: options.targetNodeId,\n });\n // Auto-sync after creation if URL is provided.\n if (object.url) {\n yield* Operation.schedule(\n FeedOperation.SyncFeed,\n { feed: Ref.make(object) },\n { spaceId: Obj.getDatabase(object)?.spaceId },\n );\n }\n return result;\n }),\n }),\n Capability.contributes(SpaceCapabilities.CreateObjectEntry, {\n id: Type.getTypename(Magazine.Magazine),\n inputSchema: Magazine.CreateMagazineSchema,\n createObject: (props, options) =>\n Effect.gen(function* () {\n const magazine = Magazine.make(props);\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object: magazine,\n target: options.target,\n targetNodeId: getMagazinesPath(options.db.spaceId),\n });\n }),\n }),\n ];\n }),\n);\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;AAIA,YAAYA,YAAY;AACxB,YAAYC,YAAY;AAExB,SAASC,kBAAkB;AAC3B,SAASC,iBAAiB;AAC1B,SAASC,KAAKC,KAAKC,YAAY;AAC/B,SAASC,sBAAsB;AAC/B,SAASC,yBAAyB;AAClC,SAASC,oBAAoBC,yBAAyBC,UAAUC,qBAAqB;AAErF,SAASC,oBAAoBC,eAAeC,UAAUC,oBAAoB;AAU1E,IAAMC,qBAA4BC,cAAO;EACvC,GAAGC,mBAAmBC,uBAAuBC;;EAE7CC,QAAQH,mBAAmBC,uBAAuBC,OAAOC,OAAOC,KAC9DC,wBAAwBC,IACtBC,cAAAA,EACE;IAAC;KACD,CAAC,EAAEJ,OAAM,MACPK,0BAA0BL,UAAU,IAAI;IAAEM,WAAWC,iBAAAA;EAAmB,CAAA,EAAGN,KAClEO,WAAI,CAACC,gBACVA,YAAYD,IAAI,CAACE,gBAAgB;IAC/BC,OAAOD,WAAWV;IAClBY,OAAOF,WAAWV;IAClBa,gBAAgBH,WAAWI;EAC7B,EAAA,CAAA,CAAA,GAGN;IAAEC,UAAU;EAAK,CAAA,CAAA,CAAA;;EAKvBC,aAAanB,mBAAmBC,uBAAuBC,OAAOiB,YAAYf,KACxEC,wBAAwBC,IACtBC,cAAAA,EAAuD;IAAC;KAAW,CAAC,EAAEJ,OAAM,MAC1EH,mBAAmBoB,SAASjB,MAAAA,IACxBkB,6BAA6BlB,QAAQ;IAAEM,WAAWC,iBAAAA;EAAmB,CAAA,EAAGN,KAC/DO,WAAI,CAACW,iBACVA,aAAaX,IAAI,CAACQ,iBAAiB;IACjCL,OAAOK,YAAYI;IACnBR,OAAOI,YAAYK,QAAQL,YAAYM,OAAON,YAAYI;EAC5D,EAAA,CAAA,GAEKG,qBAAc,MAAM,CAAA,CAAE,CAAA,IAExBC,eAAQ,CAAA,CAAE,CAAA,CAAA,CAAA;AAI7B,CAAA;AAEA,IAAMC,YAAmB7B,cAAO;EAC9B,GAAGC,mBAAmB6B,cAAc3B;;EAEpCsB,MAAaM,gBACJC,cAAO3B,KACZ4B,mBAAmB1B,IACjB2B,SAAAA,EAAyC;IAAC;KAAQ,CAAC,EAAER,IAAG,MACtDzB,mBAAmBkC,MAAMT,GAAAA,IACrBU,SAASV,KAAK;IAAEhB,WAAWC,iBAAAA;EAAmB,CAAA,EAAGN,KACxCO,WAAI,CAACyB,WAAWA,OAAOC,KAAKb,IAAI,GAChCE,qBAAc,MAAMY,MAAAA,CAAAA,IAEtBX,eAAQW,MAAAA,CAAAA,CAAAA,CAAAA,EAGvBC,YAAY;IAAEC,OAAO;EAAO,CAAA,CAAA;AAElC,CAAA;AAEA,IAAMC,2BAAkCC,aAAM5C,oBAAoB8B,SAAAA;AAElE,IAAA,wBAAee,WAAWC,WACjBC,kBAAW,aAAA;AAChB,SAAO;IACLF,WAAWG,YAAYC,kBAAkBC,mBAAmB;MAC1DC,IAAIC,KAAKC,YAAYC,aAAaA,YAAY;MAC9CC,aAAaZ;MACba,cAAc,CAACC,OAAOC,YACbC,WAAI,aAAA;AACT,cAAMC,SAAS1D,mBAAmB2D,2BAA2BJ,KAAAA;AAC7D,cAAMnB,SAAS,OAAOwB,UAAUC,OAAOC,eAAeC,WAAW;UAC/DL;UACAM,QAAQR,QAAQQ;UAChBC,cAAcT,QAAQS;QACxB,CAAA;AAEA,YAAIP,OAAOjC,KAAK;AACd,iBAAOmC,UAAUM,SACfC,cAAcC,UACd;YAAE/B,MAAMgC,IAAIC,KAAKZ,MAAAA;UAAQ,GACzB;YAAEa,SAASC,IAAIC,YAAYf,MAAAA,GAASa;UAAQ,CAAA;QAEhD;AACA,eAAOnC;MACT,CAAA;IACJ,CAAA;IACAO,WAAWG,YAAYC,kBAAkBC,mBAAmB;MAC1DC,IAAIC,KAAKC,YAAYuB,SAASA,QAAQ;MACtCrB,aAAaqB,SAASC;MACtBrB,cAAc,CAACC,OAAOC,YACbC,WAAI,aAAA;AACT,cAAMmB,WAAWF,SAASJ,KAAKf,KAAAA;AAC/B,eAAO,OAAOK,UAAUC,OAAOC,eAAeC,WAAW;UACvDL,QAAQkB;UACRZ,QAAQR,QAAQQ;UAChBC,cAAcY,iBAAiBrB,QAAQsB,GAAGP,OAAO;QACnD,CAAA;MACF,CAAA;IACJ,CAAA;;AAEJ,CAAA,CAAA;",
|
|
6
|
-
"names": ["Effect", "Schema", "Capability", "Operation", "Obj", "Ref", "Type", "SpaceOperation", "SpaceCapabilities", "AutofillAnnotation", "OptionsLookupAnnotation", "autofill", "optionsLookup", "CreateSubscription", "FeedOperation", "Magazine", "Subscription", "StandardSiteCreate", "Struct", "CreateSubscription", "StandardSiteCreateBase", "fields", "handle", "pipe", "OptionsLookupAnnotation", "set", "optionsLookup", "searchStandardSiteHandles", "corsProxy", "browserCorsProxy", "map", "suggestions", "suggestion", "value", "label", "secondaryLabel", "displayName", "combobox", "publication", "isHandle", "listStandardSitePublications", "publications", "site", "name", "url", "orElseSucceed", "succeed", "RssCreate", "RssCreateBase", "optional", "String", "AutofillAnnotation", "autofill", "isUrl", "fetchRss", "result", "feed", "undefined", "annotations", "title", "CreateSubscriptionSchema", "Union", "Capability", "makeModule", "fnUntraced", "contributes", "SpaceCapabilities", "CreateObjectEntry", "id", "Type", "getTypename", "Subscription", "inputSchema", "createObject", "props", "options", "gen", "object", "makeSubscriptionFromCreate", "Operation", "invoke", "SpaceOperation", "AddObject", "target", "targetNodeId", "schedule", "FeedOperation", "SyncFeed", "Ref", "make", "spaceId", "Obj", "getDatabase", "Magazine", "CreateMagazineSchema", "magazine", "getMagazinesPath", "db"]
|
|
7
|
-
}
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FeedOperation_exports,
|
|
3
|
-
Magazine_exports,
|
|
4
|
-
Subscription_exports
|
|
5
|
-
} from "./chunk-OYCDRSWB.mjs";
|
|
6
|
-
import {
|
|
7
|
-
publishedTimestamp
|
|
8
|
-
} from "./chunk-SAWKLGJU.mjs";
|
|
9
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
10
|
-
|
|
11
|
-
// src/operations/curate-magazine.ts
|
|
12
|
-
import * as Effect2 from "effect/Effect";
|
|
13
|
-
import * as Option from "effect/Option";
|
|
14
|
-
import * as Schema from "effect/Schema";
|
|
15
|
-
import { RunInstructions } from "@dxos/assistant-toolkit";
|
|
16
|
-
import { Operation } from "@dxos/compute";
|
|
17
|
-
import { Database as Database2, Obj, Ref } from "@dxos/echo";
|
|
18
|
-
import { log } from "@dxos/log";
|
|
19
|
-
|
|
20
|
-
// src/operations/util.ts
|
|
21
|
-
import * as Effect from "effect/Effect";
|
|
22
|
-
import { Database, Filter, Query } from "@dxos/echo";
|
|
23
|
-
var collectCandidates = (magazine) => Effect.gen(function* () {
|
|
24
|
-
const seen = new Set(magazine.posts.map((ref) => ref.target?.id ?? ref.uri));
|
|
25
|
-
const candidates = [];
|
|
26
|
-
for (const feedRef of magazine.feeds) {
|
|
27
|
-
const feed = yield* Database.load(feedRef);
|
|
28
|
-
const echoFeed = feed.feed?.target;
|
|
29
|
-
if (!echoFeed) {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
const posts = yield* Database.query(Query.select(Filter.type(Subscription_exports.Post)).from(echoFeed)).run;
|
|
33
|
-
for (const post of posts) {
|
|
34
|
-
if (seen.has(post.id)) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
seen.add(post.id);
|
|
38
|
-
candidates.push({
|
|
39
|
-
post,
|
|
40
|
-
feed
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return candidates;
|
|
45
|
-
});
|
|
46
|
-
var partitionByKeepBound = (posts, keep, isStarred = () => false) => {
|
|
47
|
-
const kept = [];
|
|
48
|
-
const candidates = [];
|
|
49
|
-
for (const post of posts) {
|
|
50
|
-
if (isStarred(post)) {
|
|
51
|
-
kept.push(post);
|
|
52
|
-
} else {
|
|
53
|
-
candidates.push(post);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
candidates.sort((a, b) => publishedTimestamp(b.published) - publishedTimestamp(a.published));
|
|
57
|
-
const retained = candidates.slice(0, Math.max(0, keep));
|
|
58
|
-
const dropped = candidates.slice(Math.max(0, keep));
|
|
59
|
-
return {
|
|
60
|
-
kept: [
|
|
61
|
-
...kept,
|
|
62
|
-
...retained
|
|
63
|
-
],
|
|
64
|
-
dropped
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// src/operations/curate-magazine.ts
|
|
69
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-magazine/src/operations/curate-magazine.ts";
|
|
70
|
-
var curate_magazine_default = FeedOperation_exports.CurateMagazine.pipe(Operation.withHandler(Effect2.fnUntraced(function* ({ magazine: magazineRef }) {
|
|
71
|
-
const magazine = yield* Effect2.promise(() => magazineRef.load());
|
|
72
|
-
const validFeeds = yield* loadValidFeeds(magazine);
|
|
73
|
-
const synced = yield* syncFeeds(validFeeds);
|
|
74
|
-
const candidates = yield* collectCandidates(magazine);
|
|
75
|
-
const spaceId = Obj.getDatabase(magazine)?.spaceId;
|
|
76
|
-
const selectedEntries = candidates.length > 0 && spaceId ? yield* selectPostIds(magazine, candidates, spaceId) : [];
|
|
77
|
-
const selected = resolveSelected(candidates, selectedEntries);
|
|
78
|
-
const db = Obj.getDatabase(magazine);
|
|
79
|
-
const starredUri = db ? yield* Effect2.promise(() => Subscription_exports.findSystemTagUri(db, "starred")) : void 0;
|
|
80
|
-
const merged = [
|
|
81
|
-
...magazine.posts,
|
|
82
|
-
...selected.map(({ post }) => Ref.make(post))
|
|
83
|
-
];
|
|
84
|
-
const nextPosts = applyKeep(merged, magazine.keep ?? Subscription_exports.DEFAULT_KEEP, starredUri);
|
|
85
|
-
const curated = selected.length;
|
|
86
|
-
const changed = nextPosts.length !== magazine.posts.length || nextPosts.some((ref, index) => ref.uri !== magazine.posts[index]?.uri);
|
|
87
|
-
if (changed) {
|
|
88
|
-
Obj.update(magazine, (magazine2) => {
|
|
89
|
-
magazine2.posts = nextPosts;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
for (const { post, snippet, imageUrl } of selected) {
|
|
93
|
-
if (snippet || imageUrl) {
|
|
94
|
-
Magazine_exports.patchPostState(magazine, post.id, {
|
|
95
|
-
snippet,
|
|
96
|
-
imageUrl
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
synced,
|
|
102
|
-
curated
|
|
103
|
-
};
|
|
104
|
-
})), Operation.opaqueHandler);
|
|
105
|
-
var SYNC_CONCURRENCY = 8;
|
|
106
|
-
var loadValidFeeds = (magazine) => Effect2.forEach(magazine.feeds, (ref) => Effect2.gen(function* () {
|
|
107
|
-
const feed = yield* Database2.load(ref);
|
|
108
|
-
if (feed.feed) {
|
|
109
|
-
yield* Database2.load(feed.feed);
|
|
110
|
-
}
|
|
111
|
-
return feed;
|
|
112
|
-
}).pipe(Effect2.tapError((error) => Effect2.sync(() => log.catch(error, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 61, S: void 0 }))), Effect2.option)).pipe(Effect2.map((feeds) => feeds.flatMap(Option.toArray).filter((feed) => Boolean(feed.url))));
|
|
113
|
-
var syncFeeds = (validFeeds) => Effect2.forEach(validFeeds, (feed) => Operation.invoke(FeedOperation_exports.SyncFeed, {
|
|
114
|
-
feed: Ref.make(feed)
|
|
115
|
-
}, {
|
|
116
|
-
spaceId: Obj.getDatabase(feed)?.spaceId
|
|
117
|
-
}).pipe(Effect2.as(true), Effect2.catchAll((error) => Effect2.sync(() => (log.catch(error, {
|
|
118
|
-
feedUrl: feed.url
|
|
119
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 66, S: void 0 }), false)))), {
|
|
120
|
-
concurrency: SYNC_CONCURRENCY
|
|
121
|
-
}).pipe(Effect2.map((results) => results.filter(Boolean).length));
|
|
122
|
-
var selectPostIds = (magazine, candidates, spaceId) => Effect2.gen(function* () {
|
|
123
|
-
if (!magazine.instructions) {
|
|
124
|
-
return [];
|
|
125
|
-
}
|
|
126
|
-
const input = {
|
|
127
|
-
candidates: candidates.map(({ post, feed }) => ({
|
|
128
|
-
id: post.id,
|
|
129
|
-
feedName: feed.name,
|
|
130
|
-
title: post.title,
|
|
131
|
-
description: post.description,
|
|
132
|
-
author: post.author,
|
|
133
|
-
published: post.published,
|
|
134
|
-
link: post.link
|
|
135
|
-
}))
|
|
136
|
-
};
|
|
137
|
-
return yield* Operation.invoke(RunInstructions, {
|
|
138
|
-
instructions: magazine.instructions,
|
|
139
|
-
input
|
|
140
|
-
}, {
|
|
141
|
-
spaceId
|
|
142
|
-
}).pipe(Effect2.flatMap(Schema.decodeUnknown(Magazine_exports.CurationOutput)), Effect2.map((output) => output.posts), Effect2.catchAll((error) => Effect2.sync(() => {
|
|
143
|
-
log.warn("curation selection failed", {
|
|
144
|
-
error
|
|
145
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 97, S: this });
|
|
146
|
-
return [];
|
|
147
|
-
})));
|
|
148
|
-
});
|
|
149
|
-
var resolveSelected = (candidates, entries) => {
|
|
150
|
-
const byId = new Map(candidates.map(({ post }) => [
|
|
151
|
-
post.id,
|
|
152
|
-
post
|
|
153
|
-
]));
|
|
154
|
-
const seen = /* @__PURE__ */ new Set();
|
|
155
|
-
const selected = [];
|
|
156
|
-
for (const { id, snippet, imageUrl } of entries) {
|
|
157
|
-
const post = byId.get(id);
|
|
158
|
-
if (post && !seen.has(id)) {
|
|
159
|
-
seen.add(id);
|
|
160
|
-
selected.push({
|
|
161
|
-
post,
|
|
162
|
-
snippet,
|
|
163
|
-
imageUrl
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return selected;
|
|
168
|
-
};
|
|
169
|
-
var applyKeep = (posts, keep, starredUri) => {
|
|
170
|
-
const isStarred = (post) => Subscription_exports.hasTag(post.source?.target, post.id, starredUri);
|
|
171
|
-
const resolved = posts.map((ref) => ref.target).filter((post) => post !== void 0);
|
|
172
|
-
const unresolved = posts.filter((ref) => !ref.target);
|
|
173
|
-
const { kept } = partitionByKeepBound(resolved, keep, isStarred);
|
|
174
|
-
return [
|
|
175
|
-
...kept.map((post) => Ref.make(post)),
|
|
176
|
-
...unresolved
|
|
177
|
-
];
|
|
178
|
-
};
|
|
179
|
-
export {
|
|
180
|
-
applyKeep,
|
|
181
|
-
curate_magazine_default as default,
|
|
182
|
-
resolveSelected
|
|
183
|
-
};
|
|
184
|
-
//# sourceMappingURL=curate-magazine-7RMKSJC5.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/operations/curate-magazine.ts", "../../../src/operations/util.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport { RunInstructions } from '@dxos/assistant-toolkit';\nimport { Operation } from '@dxos/compute';\nimport { Database, Obj, Ref } from '@dxos/echo';\nimport { type EntityId, type SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nimport { FeedOperation, Magazine, Subscription } from '../types';\nimport { collectCandidates, partitionByKeepBound } from './util';\n\nexport default FeedOperation.CurateMagazine.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* ({ magazine: magazineRef }) {\n const magazine = yield* Effect.promise(() => magazineRef.load());\n\n const validFeeds = yield* loadValidFeeds(magazine);\n const synced = yield* syncFeeds(validFeeds);\n\n // Select matching Posts via the agent (single-shot structured output), then add them mechanically.\n const candidates = yield* collectCandidates(magazine);\n const spaceId = Obj.getDatabase(magazine)?.spaceId;\n const selectedEntries =\n candidates.length > 0 && spaceId ? yield* selectPostIds(magazine, candidates, spaceId) : [];\n const selected = resolveSelected(candidates, selectedEntries);\n\n // Build the next posts list as a pure function of (existing curated + newly selected), bounded\n // by the magazine's `keep`, then commit it in one update. collectCandidates already excludes\n // posts already curated, so the additions are simply appended (resolveSelected deduped them).\n const db = Obj.getDatabase(magazine);\n const starredUri = db ? yield* Effect.promise(() => Subscription.findSystemTagUri(db, 'starred')) : undefined;\n const merged = [...magazine.posts, ...selected.map(({ post }) => Ref.make(post))];\n const nextPosts = applyKeep(merged, magazine.keep ?? Subscription.DEFAULT_KEEP, starredUri);\n const curated = selected.length;\n\n const changed =\n nextPosts.length !== magazine.posts.length ||\n nextPosts.some((ref, index) => ref.uri !== magazine.posts[index]?.uri);\n if (changed) {\n Obj.update(magazine, (magazine) => {\n magazine.posts = nextPosts;\n });\n }\n\n // Write agent-generated snippet/imageUrl into per-post magazine state.\n for (const { post, snippet, imageUrl } of selected) {\n if (snippet || imageUrl) {\n Magazine.patchPostState(magazine, post.id as EntityId, { snippet, imageUrl });\n }\n }\n\n return { synced, curated };\n }),\n ),\n Operation.opaqueHandler,\n);\n\n// -- Helpers --\n\n/** Bound on concurrent feed syncs. */\nconst SYNC_CONCURRENCY = 8;\n\n/** Loads each referenced feed (and its backing ECHO feed), tolerating individual failures, keeping only syncable feeds. */\nconst loadValidFeeds = (magazine: Magazine.Magazine) =>\n Effect.forEach(magazine.feeds, (ref) =>\n Effect.gen(function* () {\n const feed = yield* Database.load(ref);\n if (feed.feed) {\n yield* Database.load(feed.feed); // Hydrate the backing ECHO feed.\n }\n return feed;\n }).pipe(\n Effect.tapError((error) => Effect.sync(() => log.catch(error))),\n Effect.option,\n ),\n ).pipe(Effect.map((feeds) => feeds.flatMap(Option.toArray).filter((feed) => Boolean(feed.url))));\n\n/** Syncs all feeds in parallel, tolerating per-feed failures; resolves to the count synced successfully. */\nconst syncFeeds = (validFeeds: readonly Subscription.Subscription[]) =>\n Effect.forEach(\n validFeeds,\n (feed) =>\n Operation.invoke(\n FeedOperation.SyncFeed,\n { feed: Ref.make(feed) },\n { spaceId: Obj.getDatabase(feed)?.spaceId },\n ).pipe(\n Effect.as(true),\n Effect.catchAll((error) => Effect.sync(() => (log.catch(error, { feedUrl: feed.url }), false))),\n ),\n { concurrency: SYNC_CONCURRENCY },\n ).pipe(Effect.map((results) => results.filter(Boolean).length));\n\n/**\n * Runs the curation agent over the candidate summaries and resolves to the selected Post entries.\n * The magazine's persisted Instructions (created with the magazine) carries the editorial brief and\n * references the Magazine skill, which RunInstructions resolves at run time. No instructions → no selection.\n * Tolerates agent/parse failures (logs → no selection).\n */\nconst selectPostIds = (\n magazine: Magazine.Magazine,\n candidates: ReadonlyArray<{ post: Subscription.Post; feed: Subscription.Subscription }>,\n spaceId: SpaceId,\n) =>\n Effect.gen(function* () {\n if (!magazine.instructions) {\n return [] as readonly (typeof Magazine.CurationOutput.Type.posts)[number][];\n }\n const input = {\n candidates: candidates.map(({ post, feed }) => ({\n id: post.id,\n feedName: feed.name,\n title: post.title,\n description: post.description,\n author: post.author,\n published: post.published,\n link: post.link,\n })),\n };\n\n return yield* Operation.invoke(RunInstructions, { instructions: magazine.instructions, input }, { spaceId }).pipe(\n Effect.flatMap(Schema.decodeUnknown(Magazine.CurationOutput)),\n Effect.map((output) => output.posts),\n Effect.catchAll((error) =>\n Effect.sync(() => {\n log.warn('curation selection failed', { error });\n return [] as readonly (typeof Magazine.CurationOutput.Type.posts)[number][];\n }),\n ),\n );\n });\n\ntype SelectedEntry = {\n post: Subscription.Post;\n snippet: string | undefined;\n imageUrl: string | undefined;\n};\n\n/** Resolves the agent's selected entries back to candidate Posts, preserving order and dropping unknown/duplicate ids. */\nexport const resolveSelected = (\n candidates: ReadonlyArray<{ post: Subscription.Post }>,\n entries: readonly { id: string; snippet?: string; imageUrl?: string }[],\n): SelectedEntry[] => {\n const byId = new Map(candidates.map(({ post }) => [post.id, post]));\n const seen = new Set<string>();\n const selected: SelectedEntry[] = [];\n for (const { id, snippet, imageUrl } of entries) {\n const post = byId.get(id);\n if (post && !seen.has(id)) {\n seen.add(id);\n selected.push({ post, snippet, imageUrl });\n }\n }\n return selected;\n};\n\n/**\n * Bounds a curated posts ref list to `keep` total (non-starred) posts: keeps all starred posts and\n * unresolved refs, plus the `keep` newest non-starred by published date. Pure; returns the retained\n * refs. Delegates the sort/slice/starred partition to {@link partitionByKeepBound}.\n */\nexport const applyKeep = (\n posts: readonly Ref.Ref<Subscription.Post>[],\n keep: number,\n starredUri: string | undefined,\n): Ref.Ref<Subscription.Post>[] => {\n const isStarred = (post: Subscription.Post) => Subscription.hasTag(post.source?.target, post.id, starredUri);\n const resolved = posts.map((ref) => ref.target).filter((post): post is Subscription.Post => post !== undefined);\n const unresolved = posts.filter((ref) => !ref.target);\n const { kept } = partitionByKeepBound(resolved, keep, isStarred);\n return [...kept.map((post) => Ref.make(post)), ...unresolved];\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Database, Filter, Query } from '@dxos/echo';\n\nimport { type Magazine, Subscription } from '../types';\nimport { publishedTimestamp } from '../util/date';\n\n/**\n * Resolves the Magazine's referenced feeds and the Posts in each feed's backing\n * ECHO queue, filtering out Posts already curated into `magazine.posts` (and cross-feed duplicates).\n */\nexport const collectCandidates = (magazine: Magazine.Magazine) =>\n Effect.gen(function* () {\n const seen = new Set(magazine.posts.map((ref) => ref.target?.id ?? ref.uri));\n const candidates: Array<{ post: Subscription.Post; feed: Subscription.Subscription }> = [];\n for (const feedRef of magazine.feeds) {\n const feed = yield* Database.load(feedRef);\n const echoFeed = feed.feed?.target;\n if (!echoFeed) {\n continue;\n }\n const posts = yield* Database.query(Query.select(Filter.type(Subscription.Post)).from(echoFeed)).run;\n for (const post of posts) {\n if (seen.has(post.id)) {\n continue;\n }\n seen.add(post.id);\n candidates.push({ post, feed });\n }\n }\n return candidates;\n });\n\n/**\n * Partitions posts into those to keep and those to drop, given a maximum\n * non-starred retention bound. Starred posts are always kept; the remaining\n * non-starred posts are sorted newest-first by `published` and the top\n * `keep` retained.\n *\n * `isStarred` is injectable; callers with a starred-tag uri pass a predicate backed by it\n * (defaults to treating nothing as starred).\n */\nexport const partitionByKeepBound = <T extends Subscription.Post>(\n posts: readonly T[],\n keep: number,\n isStarred: (post: T) => boolean = () => false,\n): { kept: T[]; dropped: T[] } => {\n const kept: T[] = [];\n const candidates: T[] = [];\n for (const post of posts) {\n if (isStarred(post)) {\n kept.push(post);\n } else {\n candidates.push(post);\n }\n }\n candidates.sort((a, b) => publishedTimestamp(b.published) - publishedTimestamp(a.published));\n const retained = candidates.slice(0, Math.max(0, keep));\n const dropped = candidates.slice(Math.max(0, keep));\n return { kept: [...kept, ...retained], dropped };\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Effect", "Option", "Schema", "RunInstructions", "Operation", "Database", "Obj", "Ref", "log", "Effect", "Database", "Filter", "Query", "collectCandidates", "magazine", "gen", "seen", "Set", "posts", "map", "ref", "target", "id", "uri", "candidates", "feedRef", "feeds", "feed", "Database", "load", "echoFeed", "query", "Query", "select", "Filter", "type", "Subscription", "Post", "from", "run", "post", "has", "add", "push", "partitionByKeepBound", "keep", "isStarred", "kept", "sort", "a", "b", "publishedTimestamp", "published", "retained", "slice", "Math", "max", "dropped", "FeedOperation", "validFeeds", "loadValidFeeds", "magazine", "synced", "syncFeeds", "candidates", "collectCandidates", "selectedEntries", "spaceId", "selected", "resolveSelected", "merged", "posts", "nextPosts", "applyKeep", "keep", "changed", "length", "ref", "index", "Obj", "Magazine", "patchPostState", "post", "snippet", "imageUrl", "curated", "Operation", "Database", "load", "feed", "pipe", "make", "getDatabase", "feedUrl", "concurrency", "SYNC_CONCURRENCY", "Effect", "map", "results", "filter", "Boolean", "input", "id", "feedName", "name", "title", "description", "author", "published", "link", "error", "seen", "byId", "push", "resolved", "target", "unresolved", "partitionByKeepBound", "isStarred", "kept"]
|
|
7
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
browserCorsProxy,
|
|
3
|
-
fetchArticle
|
|
4
|
-
} from "./chunk-AFPBWBTK.mjs";
|
|
5
|
-
import {
|
|
6
|
-
FeedOperation_exports
|
|
7
|
-
} from "./chunk-OYCDRSWB.mjs";
|
|
8
|
-
import "./chunk-APQRTYT3.mjs";
|
|
9
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
10
|
-
|
|
11
|
-
// src/operations/fetch-article-content.ts
|
|
12
|
-
import * as Effect from "effect/Effect";
|
|
13
|
-
import { Operation } from "@dxos/compute";
|
|
14
|
-
import { Database } from "@dxos/echo";
|
|
15
|
-
import { invariant } from "@dxos/invariant";
|
|
16
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-magazine/src/operations/fetch-article-content.ts";
|
|
17
|
-
var handler = FeedOperation_exports.FetchArticleContent.pipe(Operation.withHandler(Effect.fn(function* ({ post: postRef }) {
|
|
18
|
-
const post = yield* Database.load(postRef);
|
|
19
|
-
invariant(post.link, "Post has no link.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 12, S: this, A: ["post.link", "'Post has no link.'"] });
|
|
20
|
-
return yield* Effect.tryPromise({
|
|
21
|
-
try: () => fetchArticle(post.link, {
|
|
22
|
-
corsProxy: browserCorsProxy()
|
|
23
|
-
}),
|
|
24
|
-
catch: (error) => error instanceof Error ? error : new Error(String(error))
|
|
25
|
-
});
|
|
26
|
-
})));
|
|
27
|
-
var fetch_article_content_default = handler;
|
|
28
|
-
export {
|
|
29
|
-
fetch_article_content_default as default
|
|
30
|
-
};
|
|
31
|
-
//# sourceMappingURL=fetch-article-content-CXPKXIMR.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/operations/fetch-article-content.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Operation } from '@dxos/compute';\nimport { Database } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\n\nimport { FeedOperation } from '../types';\nimport { browserCorsProxy, fetchArticle } from './sources';\n\nconst handler: Operation.WithHandler<typeof FeedOperation.FetchArticleContent> = FeedOperation.FetchArticleContent.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ post: postRef }) {\n const post = yield* Database.load(postRef);\n invariant(post.link, 'Post has no link.');\n return yield* Effect.tryPromise({\n try: () => fetchArticle(post.link!, { corsProxy: browserCorsProxy() }),\n catch: (error) => (error instanceof Error ? error : new Error(String(error))),\n });\n }),\n ),\n);\n\nexport default handler;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,iBAAiB;AAC1B,SAASC,gBAAgB;AACzB,SAASC,iBAAiB;AAK1B,IAAA,eAAiFC;IAI3EC,UAAUC,sBAAW,oBAAA,KAAA,UAAA,YAAA,UAAA,WAAA,EAAA,MAAA,QAAA,GAAA;AACrB,QAAA,OAAO,OAAOC,SAAOC,KAAW,OAAA;YACzB,KAAMC,MAAAA,qBAAyB,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,aAAA,qBAAA,EAAA,CAAA;gBAAEC,kBAAWC;SAAmB,MAAA,aAAA,KAAA,MAAA;MAC5DC,WAAWA,iBAAiBC;IACtC,CAAA;IACF,OAAA,CAAA,UAAA,iBAAA,QAAA,QAAA,IAAA,MAAA,OAAA,KAAA,CAAA;EAIJ,CAAA;;;",
|
|
6
|
-
"names": ["Effect", "Operation", "Database", "invariant", "FeedOperation", "invariant", "post", "Effect", "tryPromise", "fetchArticle", "corsProxy", "browserCorsProxy", "error", "Error"]
|
|
7
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CreateSubscription_exports,
|
|
3
|
-
FeedOperation_exports,
|
|
4
|
-
Magazine_exports,
|
|
5
|
-
Subscription_exports
|
|
6
|
-
} from "./chunk-OYCDRSWB.mjs";
|
|
7
|
-
import {
|
|
8
|
-
meta
|
|
9
|
-
} from "./chunk-JFPR6OV4.mjs";
|
|
10
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
11
|
-
export {
|
|
12
|
-
CreateSubscription_exports as CreateSubscription,
|
|
13
|
-
FeedOperation_exports as FeedOperation,
|
|
14
|
-
Magazine_exports as Magazine,
|
|
15
|
-
Subscription_exports as Subscription,
|
|
16
|
-
meta
|
|
17
|
-
};
|
|
18
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
browserCorsProxy,
|
|
3
|
-
fetchArticle
|
|
4
|
-
} from "./chunk-AFPBWBTK.mjs";
|
|
5
|
-
import {
|
|
6
|
-
FeedOperation_exports,
|
|
7
|
-
Subscription_exports
|
|
8
|
-
} from "./chunk-OYCDRSWB.mjs";
|
|
9
|
-
import {
|
|
10
|
-
makeSnippet,
|
|
11
|
-
stripHtml
|
|
12
|
-
} from "./chunk-APQRTYT3.mjs";
|
|
13
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
14
|
-
|
|
15
|
-
// src/operations/load-post-content.ts
|
|
16
|
-
import * as Effect from "effect/Effect";
|
|
17
|
-
import { getSpace } from "@dxos/client/echo";
|
|
18
|
-
import { Operation } from "@dxos/compute";
|
|
19
|
-
import { invariant } from "@dxos/invariant";
|
|
20
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-magazine/src/operations/load-post-content.ts";
|
|
21
|
-
var load_post_content_default = FeedOperation_exports.LoadPostContent.pipe(Operation.withHandler(Effect.fn(function* ({ post: postRef, force }) {
|
|
22
|
-
const post = postRef.target;
|
|
23
|
-
invariant(post, "Post ref target not loaded.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 19, S: this, A: ["post", "'Post ref target not loaded.'"] });
|
|
24
|
-
const subscription = post.source?.target;
|
|
25
|
-
if (!subscription || !post.link) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const space = getSpace(subscription);
|
|
29
|
-
invariant(space, "Subscription is not in a space.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 25, S: this, A: ["space", "'Subscription is not in a space.'"] });
|
|
30
|
-
if (!force) {
|
|
31
|
-
const existing = yield* Effect.tryPromise(() => Subscription_exports.findPostContent(subscription, post));
|
|
32
|
-
if (existing) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
const inlineContent = post.content;
|
|
37
|
-
if (subscription.type === "standard-site" && inlineContent) {
|
|
38
|
-
yield* Effect.tryPromise(() => Subscription_exports.appendPostContent(space, subscription, {
|
|
39
|
-
post,
|
|
40
|
-
text: inlineContent,
|
|
41
|
-
snippet: makeSnippet(stripHtml(inlineContent))
|
|
42
|
-
}));
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
yield* Effect.tryPromise({
|
|
46
|
-
try: async () => {
|
|
47
|
-
const { text, imageUrls } = await fetchArticle(post.link, {
|
|
48
|
-
corsProxy: browserCorsProxy()
|
|
49
|
-
});
|
|
50
|
-
if (text) {
|
|
51
|
-
await Subscription_exports.appendPostContent(space, subscription, {
|
|
52
|
-
post,
|
|
53
|
-
text,
|
|
54
|
-
snippet: makeSnippet(stripHtml(text)),
|
|
55
|
-
imageUrl: imageUrls[0]
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
catch: (error) => error instanceof Error ? error : new Error(String(error))
|
|
60
|
-
});
|
|
61
|
-
})));
|
|
62
|
-
export {
|
|
63
|
-
load_post_content_default as default
|
|
64
|
-
};
|
|
65
|
-
//# sourceMappingURL=load-post-content-H3S4TKVM.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/operations/load-post-content.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { getSpace } from '@dxos/client/echo';\nimport { Operation } from '@dxos/compute';\nimport { invariant } from '@dxos/invariant';\n\nimport { FeedOperation, Subscription } from '../types';\nimport { makeSnippet, stripHtml } from '../util/text';\nimport { browserCorsProxy, fetchArticle } from './sources';\n\nexport default FeedOperation.LoadPostContent.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ post: postRef, force }) {\n // The Post is a queue item (its source Subscription lives in space.db).\n // Resolve the source Subscription first; everything that needs a\n // Database / Space binding comes from there. The Post's own\n // `Obj.getDatabase` link isn't reliably set on every code path that\n // produces a queue-decoded proxy, but the Subscription is always in\n // space.db.\n const post = postRef.target;\n invariant(post, 'Post ref target not loaded.');\n const subscription = post.source?.target;\n if (!subscription || !post.link) {\n return;\n }\n const space = getSpace(subscription);\n invariant(space, 'Subscription is not in a space.');\n // Idempotent by default (first-open auto-load); `force` re-fetches for the reader's refresh.\n if (!force) {\n const existing = yield* Effect.tryPromise(() => Subscription.findPostContent(subscription, post));\n if (existing) {\n return;\n }\n }\n\n // Standard.site documents carry the full article body inline (`Post.content`), so the reader\n // renders offline without a second network round-trip. Gated on the feed type: RSS keeps the\n // HTTP fetch path because its `content:encoded` is frequently a truncated summary, not the full\n // body.\n const inlineContent = post.content;\n if (subscription.type === 'standard-site' && inlineContent) {\n yield* Effect.tryPromise(() =>\n Subscription.appendPostContent(space, subscription, {\n post,\n text: inlineContent,\n snippet: makeSnippet(stripHtml(inlineContent)),\n }),\n );\n return;\n }\n\n yield* Effect.tryPromise({\n try: async () => {\n // In the browser, route through the dev-server CORS proxy. Server-side callers\n // (e.g. agent operations) pass no proxy and fetch directly.\n const { text, imageUrls } = await fetchArticle(post.link!, { corsProxy: browserCorsProxy() });\n if (text) {\n // Store the body plus refined snippet/imageUrl derived from the full article — preferred\n // over the description-derived defaults wherever the Post is rendered.\n await Subscription.appendPostContent(space, subscription, {\n post,\n text,\n snippet: makeSnippet(stripHtml(text)),\n imageUrl: imageUrls[0],\n });\n }\n },\n catch: (error) => (error instanceof Error ? error : new Error(String(error))),\n });\n }),\n ),\n);\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,gBAAgB;AACzB,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB;AAM1B,IAAA,eAAeC;IAIT,4BAAA,sBAAA,gBAAA,KAAA,UAAA,YAAiE,UAAA,WAAA,EAAA,MAAA,SAAA,MAAA,GAAA;AAOjE,QAAMC,OAAAA,QAAeC;AACrB,YAAKD,MAAAA,+BAA4B,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,QAAA,+BAAA,EAAA,CAAA;QAC/B,eAAA,KAAA,QAAA;AACF,MAAA,CAAA,gBAAA,CAAA,KAAA,MAAA;AACA;EACAE;AACA,QAAA,QAAA,SAAA,YAAA;AACA,YAAKC,OAAO,mCAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,SAAA,mCAAA,EAAA,CAAA;MAEV,CAAA,OAAIC;UACF,WAAA,OAAA,kBAAA,MAAA,qBAAA,gBAAA,cAAA,IAAA,CAAA;AACF,QAAA,UAAA;AACF;IAEA;EACA;QAKE,gBAAcC,KAAAA;mBAEVJ,SAAAA,mBAAAA,eAAAA;WACMK,kBAAAA,MAAAA,qBAAAA,kBAAAA,OAAAA,cAAAA;MACNC;MACF,MAAA;MAEF,SAAA,YAAA,UAAA,aAAA,CAAA;IACF,CAAA,CAAA;AAEA;;SAEI,kBAAA;SACA,YAAA;AAC2F,YAAA,EAAA,MAAA,UAAA,IAAA,MAAA,aAAA,KAAA,MAAA;QACvFC,WAAM,iBAAA;;UAER,MAAA;cAGEA,qBAAAA,kBAAAA,OAAAA,cAAAA;UACAD;UACAE;UACF,SAAA,YAAA,UAAA,IAAA,CAAA;UACF,UAAA,UAAA,CAAA;QACF,CAAA;MACAC;IACF;IAGJ,OAAA,CAAA,UAAA,iBAAA,QAAA,QAAA,IAAA,MAAA,OAAA,KAAA,CAAA;;;",
|
|
6
|
-
"names": ["Effect", "getSpace", "Operation", "invariant", "FeedOperation", "subscription", "post", "invariant", "force", "existing", "tryPromise", "inlineContent", "snippet", "text", "imageUrl", "catch"]
|
|
7
|
-
}
|