@dxos/plugin-magazine 0.0.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.
- package/LICENSE +105 -0
- package/PLUGIN.mdl +653 -0
- package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs +90 -0
- package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs.map +7 -0
- package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs +97 -0
- package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs.map +7 -0
- package/dist/lib/neutral/MagazineArticle-DEUTR23F.mjs +325 -0
- package/dist/lib/neutral/MagazineArticle-DEUTR23F.mjs.map +7 -0
- package/dist/lib/neutral/MagazinePlugin.mjs +62 -0
- package/dist/lib/neutral/MagazinePlugin.mjs.map +7 -0
- package/dist/lib/neutral/MagazinePlugin.workerd.mjs +12 -0
- package/dist/lib/neutral/MagazinePlugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/PostArticle-RERHXPXC.mjs +230 -0
- package/dist/lib/neutral/PostArticle-RERHXPXC.mjs.map +7 -0
- package/dist/lib/neutral/PostCard-VDGN7BBA.mjs +60 -0
- package/dist/lib/neutral/PostCard-VDGN7BBA.mjs.map +7 -0
- package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs +121 -0
- package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +21 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/neutral/chunk-3K4AQKBZ.mjs +12 -0
- package/dist/lib/neutral/chunk-3K4AQKBZ.mjs.map +7 -0
- package/dist/lib/neutral/chunk-AFPBWBTK.mjs +591 -0
- package/dist/lib/neutral/chunk-AFPBWBTK.mjs.map +7 -0
- package/dist/lib/neutral/chunk-APQRTYT3.mjs +57 -0
- package/dist/lib/neutral/chunk-APQRTYT3.mjs.map +7 -0
- package/dist/lib/neutral/chunk-GU725ZF4.mjs +11 -0
- package/dist/lib/neutral/chunk-GU725ZF4.mjs.map +7 -0
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
- package/dist/lib/neutral/chunk-JFPR6OV4.mjs +60 -0
- package/dist/lib/neutral/chunk-JFPR6OV4.mjs.map +7 -0
- package/dist/lib/neutral/chunk-KTYLUOUG.mjs +36 -0
- package/dist/lib/neutral/chunk-KTYLUOUG.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MBPX7RPI.mjs +14 -0
- package/dist/lib/neutral/chunk-MBPX7RPI.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MJ2AY2CK.mjs +8 -0
- package/dist/lib/neutral/chunk-MJ2AY2CK.mjs.map +7 -0
- package/dist/lib/neutral/chunk-OYCDRSWB.mjs +624 -0
- package/dist/lib/neutral/chunk-OYCDRSWB.mjs.map +7 -0
- package/dist/lib/neutral/chunk-SAWKLGJU.mjs +28 -0
- package/dist/lib/neutral/chunk-SAWKLGJU.mjs.map +7 -0
- package/dist/lib/neutral/chunk-XCNCK47N.mjs +15 -0
- package/dist/lib/neutral/chunk-XCNCK47N.mjs.map +7 -0
- package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs +59 -0
- package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +338 -0
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/containers/index.mjs +17 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/neutral/create-object-SYZMRR4H.mjs +98 -0
- package/dist/lib/neutral/create-object-SYZMRR4H.mjs.map +7 -0
- package/dist/lib/neutral/curate-magazine-MA6OLK2X.mjs +184 -0
- package/dist/lib/neutral/curate-magazine-MA6OLK2X.mjs.map +7 -0
- package/dist/lib/neutral/fetch-article-content-CZO6D3QD.mjs +31 -0
- package/dist/lib/neutral/fetch-article-content-CZO6D3QD.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +18 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/load-post-content-XGL6VFF6.mjs +65 -0
- package/dist/lib/neutral/load-post-content-XGL6VFF6.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +8 -0
- package/dist/lib/neutral/meta.mjs.map +7 -0
- package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs +18 -0
- package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs.map +7 -0
- package/dist/lib/neutral/operation-handler-JE3743BU.mjs +8 -0
- package/dist/lib/neutral/operation-handler-JE3743BU.mjs.map +7 -0
- package/dist/lib/neutral/operations/index.mjs +8 -0
- package/dist/lib/neutral/operations/index.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +16 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/plugin.workerd.mjs +16 -0
- package/dist/lib/neutral/plugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/react-surface-TZESAMG2.mjs +60 -0
- package/dist/lib/neutral/react-surface-TZESAMG2.mjs.map +7 -0
- package/dist/lib/neutral/routine-templates-A2XTJOZO.mjs +52 -0
- package/dist/lib/neutral/routine-templates-A2XTJOZO.mjs.map +7 -0
- package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs +8 -0
- package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs.map +7 -0
- package/dist/lib/neutral/skills/index.mjs +46 -0
- package/dist/lib/neutral/skills/index.mjs.map +7 -0
- package/dist/lib/neutral/sync-feed-UZX2XHSQ.mjs +99 -0
- package/dist/lib/neutral/sync-feed-UZX2XHSQ.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +81 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/neutral/types/index.mjs +14 -0
- package/dist/lib/neutral/types/index.mjs.map +7 -0
- package/dist/types/dx.config.d.ts +28 -0
- package/dist/types/dx.config.d.ts.map +1 -0
- package/dist/types/src/MagazinePlugin.d.ts +4 -0
- package/dist/types/src/MagazinePlugin.d.ts.map +1 -0
- package/dist/types/src/MagazinePlugin.test.d.ts +2 -0
- package/dist/types/src/MagazinePlugin.test.d.ts.map +1 -0
- package/dist/types/src/MagazinePlugin.workerd.d.ts +4 -0
- package/dist/types/src/MagazinePlugin.workerd.d.ts.map +1 -0
- package/dist/types/src/atoms/atoms.test.d.ts +2 -0
- package/dist/types/src/atoms/atoms.test.d.ts.map +1 -0
- package/dist/types/src/atoms/index.d.ts +7 -0
- package/dist/types/src/atoms/index.d.ts.map +1 -0
- package/dist/types/src/atoms/magazine-posts.d.ts +16 -0
- package/dist/types/src/atoms/magazine-posts.d.ts.map +1 -0
- package/dist/types/src/atoms/post-content.d.ts +7 -0
- package/dist/types/src/atoms/post-content.d.ts.map +1 -0
- package/dist/types/src/atoms/post-curation.d.ts +16 -0
- package/dist/types/src/atoms/post-curation.d.ts.map +1 -0
- package/dist/types/src/atoms/post-display.d.ts +22 -0
- package/dist/types/src/atoms/post-display.d.ts.map +1 -0
- package/dist/types/src/atoms/post-read.d.ts +14 -0
- package/dist/types/src/atoms/post-read.d.ts.map +1 -0
- package/dist/types/src/atoms/post-tags.d.ts +16 -0
- package/dist/types/src/atoms/post-tags.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +5 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +5 -0
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +10 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/navigation-resolver.d.ts +5 -0
- package/dist/types/src/capabilities/navigation-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/routine-templates.d.ts +5 -0
- package/dist/types/src/capabilities/routine-templates.d.ts.map +1 -0
- package/dist/types/src/capabilities/skill-definition.d.ts +5 -0
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -0
- package/dist/types/src/components/PostContent/PostContent.d.ts +30 -0
- package/dist/types/src/components/PostContent/PostContent.d.ts.map +1 -0
- package/dist/types/src/components/PostContent/PostContent.test.d.ts +2 -0
- package/dist/types/src/components/PostContent/PostContent.test.d.ts.map +1 -0
- package/dist/types/src/components/PostContent/index.d.ts +2 -0
- package/dist/types/src/components/PostContent/index.d.ts.map +1 -0
- package/dist/types/src/components/PostStack/PostStack.d.ts +17 -0
- package/dist/types/src/components/PostStack/PostStack.d.ts.map +1 -0
- package/dist/types/src/components/PostStack/PostStack.stories.d.ts +10 -0
- package/dist/types/src/components/PostStack/PostStack.stories.d.ts.map +1 -0
- package/dist/types/src/components/PostStack/index.d.ts +2 -0
- package/dist/types/src/components/PostStack/index.d.ts.map +1 -0
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts +23 -0
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts.map +1 -0
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.stories.d.ts +8 -0
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.stories.d.ts.map +1 -0
- package/dist/types/src/components/SubscriptionStack/index.d.ts +2 -0
- package/dist/types/src/components/SubscriptionStack/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +4 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts +6 -0
- package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts.map +1 -0
- package/dist/types/src/containers/FeedArticle/FeedArticle.stories.d.ts +12 -0
- package/dist/types/src/containers/FeedArticle/FeedArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/FeedArticle/FeedToolbar.d.ts +10 -0
- package/dist/types/src/containers/FeedArticle/FeedToolbar.d.ts.map +1 -0
- package/dist/types/src/containers/FeedArticle/index.d.ts +2 -0
- package/dist/types/src/containers/FeedArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts +6 -0
- package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts.map +1 -0
- package/dist/types/src/containers/FeedProperties/index.d.ts +2 -0
- package/dist/types/src/containers/FeedProperties/index.d.ts.map +1 -0
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts +6 -0
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts.map +1 -0
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.stories.d.ts +9 -0
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts +11 -0
- package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts.map +1 -0
- package/dist/types/src/containers/MagazineArticle/index.d.ts +2 -0
- package/dist/types/src/containers/MagazineArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts +18 -0
- package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts.map +1 -0
- package/dist/types/src/containers/PostArticle/PostArticle.d.ts +6 -0
- package/dist/types/src/containers/PostArticle/PostArticle.d.ts.map +1 -0
- package/dist/types/src/containers/PostArticle/PostArticle.stories.d.ts +8 -0
- package/dist/types/src/containers/PostArticle/PostArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/PostArticle/PostToolbar.d.ts +19 -0
- package/dist/types/src/containers/PostArticle/PostToolbar.d.ts.map +1 -0
- package/dist/types/src/containers/PostArticle/index.d.ts +2 -0
- package/dist/types/src/containers/PostArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/PostCard/PostCard.d.ts +11 -0
- package/dist/types/src/containers/PostCard/PostCard.d.ts.map +1 -0
- package/dist/types/src/containers/PostCard/index.d.ts +2 -0
- package/dist/types/src/containers/PostCard/index.d.ts.map +1 -0
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts +5 -0
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts.map +1 -0
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.d.ts +8 -0
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/SubscriptionsArticle/index.d.ts +2 -0
- package/dist/types/src/containers/SubscriptionsArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +7 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +33 -0
- package/dist/types/src/meta.d.ts.map +1 -0
- package/dist/types/src/operations/clear-magazine.d.ts +10 -0
- package/dist/types/src/operations/clear-magazine.d.ts.map +1 -0
- package/dist/types/src/operations/curate-magazine.d.ts +25 -0
- package/dist/types/src/operations/curate-magazine.d.ts.map +1 -0
- package/dist/types/src/operations/curate-magazine.skill.test.d.ts +2 -0
- package/dist/types/src/operations/curate-magazine.skill.test.d.ts.map +1 -0
- package/dist/types/src/operations/curate-magazine.test.d.ts +2 -0
- package/dist/types/src/operations/curate-magazine.test.d.ts.map +1 -0
- package/dist/types/src/operations/extraction/article.d.ts +37 -0
- package/dist/types/src/operations/extraction/article.d.ts.map +1 -0
- package/dist/types/src/operations/extraction/article.test.d.ts +2 -0
- package/dist/types/src/operations/extraction/article.test.d.ts.map +1 -0
- package/dist/types/src/operations/extraction/index.d.ts +2 -0
- package/dist/types/src/operations/extraction/index.d.ts.map +1 -0
- package/dist/types/src/operations/fetch-article-content.d.ts +5 -0
- package/dist/types/src/operations/fetch-article-content.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/load-post-content.d.ts +8 -0
- package/dist/types/src/operations/load-post-content.d.ts.map +1 -0
- package/dist/types/src/operations/sources/article.d.ts +24 -0
- package/dist/types/src/operations/sources/article.d.ts.map +1 -0
- package/dist/types/src/operations/sources/cors.d.ts +12 -0
- package/dist/types/src/operations/sources/cors.d.ts.map +1 -0
- package/dist/types/src/operations/sources/feed-fetcher.d.ts +22 -0
- package/dist/types/src/operations/sources/feed-fetcher.d.ts.map +1 -0
- package/dist/types/src/operations/sources/feed-fetcher.test.d.ts +2 -0
- package/dist/types/src/operations/sources/feed-fetcher.test.d.ts.map +1 -0
- package/dist/types/src/operations/sources/http.d.ts +9 -0
- package/dist/types/src/operations/sources/http.d.ts.map +1 -0
- package/dist/types/src/operations/sources/index.d.ts +6 -0
- package/dist/types/src/operations/sources/index.d.ts.map +1 -0
- package/dist/types/src/operations/sources/rss.d.ts +4 -0
- package/dist/types/src/operations/sources/rss.d.ts.map +1 -0
- package/dist/types/src/operations/sources/rss.test.d.ts +2 -0
- package/dist/types/src/operations/sources/rss.test.d.ts.map +1 -0
- package/dist/types/src/operations/sources/standard-site.d.ts +33 -0
- package/dist/types/src/operations/sources/standard-site.d.ts.map +1 -0
- package/dist/types/src/operations/sync-feed.d.ts +5 -0
- package/dist/types/src/operations/sync-feed.d.ts.map +1 -0
- package/dist/types/src/operations/sync-feed.test.d.ts +2 -0
- package/dist/types/src/operations/sync-feed.test.d.ts.map +1 -0
- package/dist/types/src/operations/util.d.ts +25 -0
- package/dist/types/src/operations/util.d.ts.map +1 -0
- package/dist/types/src/operations/util.test.d.ts +2 -0
- package/dist/types/src/operations/util.test.d.ts.map +1 -0
- package/dist/types/src/paths.d.ts +3 -0
- package/dist/types/src/paths.d.ts.map +1 -0
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/plugin.workerd.d.ts +3 -0
- package/dist/types/src/plugin.workerd.d.ts.map +1 -0
- package/dist/types/src/skills/index.d.ts +2 -0
- package/dist/types/src/skills/index.d.ts.map +1 -0
- package/dist/types/src/skills/magazine-skill.d.ts +4 -0
- package/dist/types/src/skills/magazine-skill.d.ts.map +1 -0
- package/dist/types/src/stories/ArticleExtractor.stories.d.ts +267 -0
- package/dist/types/src/stories/ArticleExtractor.stories.d.ts.map +1 -0
- package/dist/types/src/stories/MagazineCurate.stories.d.ts +32 -0
- package/dist/types/src/stories/MagazineCurate.stories.d.ts.map +1 -0
- package/dist/types/src/stories/theregister-fixture.test.d.ts +2 -0
- package/dist/types/src/stories/theregister-fixture.test.d.ts.map +1 -0
- package/dist/types/src/templates/magazine-curation.d.ts +7 -0
- package/dist/types/src/templates/magazine-curation.d.ts.map +1 -0
- package/dist/types/src/testing/builder.d.ts +28 -0
- package/dist/types/src/testing/builder.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +247 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/src/types/CreateSubscription.d.ts +29 -0
- package/dist/types/src/types/CreateSubscription.d.ts.map +1 -0
- package/dist/types/src/types/FeedOperation.d.ts +52 -0
- package/dist/types/src/types/FeedOperation.d.ts.map +1 -0
- package/dist/types/src/types/Magazine.d.ts +87 -0
- package/dist/types/src/types/Magazine.d.ts.map +1 -0
- package/dist/types/src/types/Magazine.test.d.ts +2 -0
- package/dist/types/src/types/Magazine.test.d.ts.map +1 -0
- package/dist/types/src/types/Subscription.d.ts +144 -0
- package/dist/types/src/types/Subscription.d.ts.map +1 -0
- package/dist/types/src/types/Subscription.test.d.ts +2 -0
- package/dist/types/src/types/Subscription.test.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +5 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/util/date.d.ts +8 -0
- package/dist/types/src/util/date.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +4 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/post-content.d.ts +14 -0
- package/dist/types/src/util/post-content.d.ts.map +1 -0
- package/dist/types/src/util/text.d.ts +18 -0
- package/dist/types/src/util/text.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dx.config.ts +48 -0
- package/package.json +164 -0
- package/src/MagazinePlugin.test.ts +36 -0
- package/src/MagazinePlugin.tsx +61 -0
- package/src/MagazinePlugin.workerd.ts +31 -0
- package/src/atoms/atoms.test.ts +323 -0
- package/src/atoms/index.ts +10 -0
- package/src/atoms/magazine-posts.ts +70 -0
- package/src/atoms/post-content.ts +34 -0
- package/src/atoms/post-curation.ts +36 -0
- package/src/atoms/post-display.ts +59 -0
- package/src/atoms/post-read.ts +40 -0
- package/src/atoms/post-tags.ts +66 -0
- package/src/capabilities/app-graph-builder.ts +125 -0
- package/src/capabilities/create-object.ts +127 -0
- package/src/capabilities/index.ts +17 -0
- package/src/capabilities/navigation-resolver.ts +21 -0
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/react-surface.tsx +53 -0
- package/src/capabilities/routine-templates.ts +16 -0
- package/src/capabilities/skill-definition.ts +14 -0
- package/src/components/PostContent/PostContent.test.ts +81 -0
- package/src/components/PostContent/PostContent.tsx +111 -0
- package/src/components/PostContent/index.ts +5 -0
- package/src/components/PostStack/PostStack.stories.tsx +39 -0
- package/src/components/PostStack/PostStack.tsx +151 -0
- package/src/components/PostStack/index.ts +5 -0
- package/src/components/SubscriptionStack/SubscriptionStack.stories.tsx +52 -0
- package/src/components/SubscriptionStack/SubscriptionStack.tsx +161 -0
- package/src/components/SubscriptionStack/index.ts +5 -0
- package/src/components/index.ts +7 -0
- package/src/containers/FeedArticle/FeedArticle.stories.tsx +102 -0
- package/src/containers/FeedArticle/FeedArticle.tsx +68 -0
- package/src/containers/FeedArticle/FeedToolbar.tsx +47 -0
- package/src/containers/FeedArticle/index.ts +5 -0
- package/src/containers/FeedProperties/FeedProperties.tsx +107 -0
- package/src/containers/FeedProperties/index.ts +5 -0
- package/src/containers/MagazineArticle/MagazineArticle.stories.tsx +244 -0
- package/src/containers/MagazineArticle/MagazineArticle.tsx +146 -0
- package/src/containers/MagazineArticle/MagazineTile.tsx +88 -0
- package/src/containers/MagazineArticle/index.ts +5 -0
- package/src/containers/MagazineArticle/useToolbar.tsx +145 -0
- package/src/containers/PostArticle/PostArticle.stories.tsx +117 -0
- package/src/containers/PostArticle/PostArticle.tsx +140 -0
- package/src/containers/PostArticle/PostToolbar.tsx +120 -0
- package/src/containers/PostArticle/index.ts +5 -0
- package/src/containers/PostCard/PostCard.tsx +70 -0
- package/src/containers/PostCard/index.ts +5 -0
- package/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.tsx +80 -0
- package/src/containers/SubscriptionsArticle/SubscriptionsArticle.tsx +99 -0
- package/src/containers/SubscriptionsArticle/index.ts +5 -0
- package/src/containers/index.ts +11 -0
- package/src/index.ts +6 -0
- package/src/meta.ts +9 -0
- package/src/operations/clear-magazine.ts +83 -0
- package/src/operations/curate-magazine.skill.conversations.json +1 -0
- package/src/operations/curate-magazine.skill.test.ts +167 -0
- package/src/operations/curate-magazine.test.ts +91 -0
- package/src/operations/curate-magazine.ts +178 -0
- package/src/operations/extraction/article.test.ts +154 -0
- package/src/operations/extraction/article.ts +270 -0
- package/src/operations/extraction/index.ts +5 -0
- package/src/operations/fetch-article-content.ts +27 -0
- package/src/operations/index.ts +13 -0
- package/src/operations/load-post-content.ts +76 -0
- package/src/operations/sources/article.ts +122 -0
- package/src/operations/sources/cors.ts +19 -0
- package/src/operations/sources/feed-fetcher.test.ts +200 -0
- package/src/operations/sources/feed-fetcher.ts +26 -0
- package/src/operations/sources/http.ts +42 -0
- package/src/operations/sources/index.ts +9 -0
- package/src/operations/sources/rss.test.ts +201 -0
- package/src/operations/sources/rss.ts +138 -0
- package/src/operations/sources/standard-site.ts +381 -0
- package/src/operations/sources/testing/feed.xml +477 -0
- package/src/operations/sync-feed.test.ts +146 -0
- package/src/operations/sync-feed.ts +140 -0
- package/src/operations/util.test.ts +67 -0
- package/src/operations/util.ts +65 -0
- package/src/paths.ts +14 -0
- package/src/plugin.ts +11 -0
- package/src/plugin.workerd.ts +6 -0
- package/src/skills/index.ts +5 -0
- package/src/skills/magazine-skill.ts +45 -0
- package/src/stories/ArticleExtractor.stories.tsx +204 -0
- package/src/stories/MagazineCurate.stories.tsx +217 -0
- package/src/stories/fixtures/theregister-ai.xml +45 -0
- package/src/stories/theregister-fixture.test.ts +35 -0
- package/src/templates/magazine-curation.ts +47 -0
- package/src/testing/builder.ts +77 -0
- package/src/testing/index.ts +5 -0
- package/src/translations.ts +81 -0
- package/src/types/CreateSubscription.ts +61 -0
- package/src/types/FeedOperation.ts +134 -0
- package/src/types/Magazine.test.ts +69 -0
- package/src/types/Magazine.ts +214 -0
- package/src/types/Subscription.test.ts +171 -0
- package/src/types/Subscription.ts +366 -0
- package/src/types/index.ts +8 -0
- package/src/util/date.ts +27 -0
- package/src/util/index.ts +7 -0
- package/src/util/post-content.ts +19 -0
- package/src/util/text.ts +98 -0
- package/src/vite-env.d.ts +10 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decodeEntities,
|
|
3
|
+
makeSnippet
|
|
4
|
+
} from "./chunk-APQRTYT3.mjs";
|
|
5
|
+
|
|
6
|
+
// src/operations/sources/cors.ts
|
|
7
|
+
var CORS_PROXY = "/api/rss?url=";
|
|
8
|
+
var browserCorsProxy = () => typeof window !== "undefined" ? CORS_PROXY : void 0;
|
|
9
|
+
var applyCorsProxy = (url, proxy) => proxy ? `${proxy}${encodeURIComponent(url)}` : url;
|
|
10
|
+
|
|
11
|
+
// src/operations/extraction/article.ts
|
|
12
|
+
import Defuddle from "defuddle/full";
|
|
13
|
+
var isDocumentParserAvailable = () => typeof DOMParser !== "undefined";
|
|
14
|
+
var collectImageUrls = (lead, contentHtml) => {
|
|
15
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16
|
+
const urls = [];
|
|
17
|
+
const push = (url) => {
|
|
18
|
+
if (!url || url.startsWith("data:") || seen.has(url)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
seen.add(url);
|
|
22
|
+
urls.push(url);
|
|
23
|
+
};
|
|
24
|
+
push(lead);
|
|
25
|
+
const imgRegex = /<img\b[^>]+src=["']([^"']+)["']/gi;
|
|
26
|
+
let match;
|
|
27
|
+
while ((match = imgRegex.exec(contentHtml)) != null) {
|
|
28
|
+
push(match[1]);
|
|
29
|
+
}
|
|
30
|
+
return urls;
|
|
31
|
+
};
|
|
32
|
+
var CHROME_CLASS_PATTERN = /(?:^|[\s_-])(?:tag|topic|related|recirc|footer|sidebar|widget|share|social|comments?|disqus|recommend|more[-_]from|read[-_]next|outbrain|taboola)(?:[\s_-]|$)/i;
|
|
33
|
+
var CHROME_HREF_PATTERN = /\/(?:tags?|topics?|categor(?:y|ies)|authors?|related|recommended)\//i;
|
|
34
|
+
var isHeading = (el) => /^H[1-6]$/i.test(el.tagName);
|
|
35
|
+
var isLinkOnlyList = (el) => {
|
|
36
|
+
if (el.tagName !== "UL" && el.tagName !== "OL") {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const items = Array.from(el.children).filter((child) => child.tagName === "LI");
|
|
40
|
+
if (items.length === 0) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return items.every((li) => {
|
|
44
|
+
const links = li.querySelectorAll("a");
|
|
45
|
+
if (links.length !== 1) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const text2 = (li.textContent ?? "").trim();
|
|
49
|
+
const linkText = (links[0].textContent ?? "").trim();
|
|
50
|
+
return text2.length > 0 && Math.abs(text2.length - linkText.length) <= 4;
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
var isTagURLBlock = (el) => {
|
|
54
|
+
const links = Array.from(el.querySelectorAll("a[href]"));
|
|
55
|
+
if (links.length < 2) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const matching = links.filter((anchor) => CHROME_HREF_PATTERN.test(anchor.getAttribute("href") ?? ""));
|
|
59
|
+
return matching.length / links.length > 0.6;
|
|
60
|
+
};
|
|
61
|
+
var hasNoBodyContent = (el) => el.querySelector("p, blockquote, pre, code, figure, img, table") == null;
|
|
62
|
+
var isChromeElement = (el) => {
|
|
63
|
+
const tag = el.tagName;
|
|
64
|
+
if (tag === "ASIDE" || tag === "NAV" || tag === "FOOTER") {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
const role = el.getAttribute("role");
|
|
68
|
+
if (role === "navigation" || role === "complementary" || role === "contentinfo") {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (isLinkOnlyList(el)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
if (!hasNoBodyContent(el)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (isTagURLBlock(el)) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
const classNameAndId = `${(el.getAttribute("class") ?? "").toString()} ${el.id ?? ""}`;
|
|
81
|
+
if (CHROME_CLASS_PATTERN.test(classNameAndId)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
};
|
|
86
|
+
var findContentRoot = (doc) => doc.querySelector("article") ?? doc.querySelector("main") ?? doc.querySelector('[role="main"]') ?? doc.body;
|
|
87
|
+
var pruneChromeDescendants = (root) => {
|
|
88
|
+
const candidates = Array.from(root.querySelectorAll("*"));
|
|
89
|
+
for (const el of candidates) {
|
|
90
|
+
if (!root.contains(el)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (isChromeElement(el)) {
|
|
94
|
+
el.remove();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
var trimDanglingTrailingHeading = (root) => {
|
|
99
|
+
let cursor = root.lastElementChild;
|
|
100
|
+
while (cursor && isHeading(cursor) && cursor.nextElementSibling == null) {
|
|
101
|
+
const previous = cursor.previousElementSibling;
|
|
102
|
+
cursor.remove();
|
|
103
|
+
cursor = previous;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var pruneTrailingChrome = (doc) => {
|
|
107
|
+
const root = findContentRoot(doc);
|
|
108
|
+
if (!root) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const originalLastChild = root.lastElementChild;
|
|
112
|
+
pruneChromeDescendants(root);
|
|
113
|
+
if (originalLastChild && !root.contains(originalLastChild)) {
|
|
114
|
+
trimDanglingTrailingHeading(root);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var mapResult = (result) => {
|
|
118
|
+
const lead = result.image || void 0;
|
|
119
|
+
return {
|
|
120
|
+
markdown: result.contentMarkdown ?? "",
|
|
121
|
+
html: result.content ?? "",
|
|
122
|
+
title: result.title || void 0,
|
|
123
|
+
author: result.author || void 0,
|
|
124
|
+
description: result.description || void 0,
|
|
125
|
+
published: result.published || void 0,
|
|
126
|
+
image: lead,
|
|
127
|
+
domain: result.domain || void 0,
|
|
128
|
+
imageUrls: collectImageUrls(lead, result.content ?? ""),
|
|
129
|
+
wordCount: result.wordCount
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
var extractArticle = async (html, url) => {
|
|
133
|
+
if (!html) {
|
|
134
|
+
return {
|
|
135
|
+
markdown: "",
|
|
136
|
+
html: "",
|
|
137
|
+
imageUrls: []
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (isDocumentParserAvailable()) {
|
|
141
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
142
|
+
pruneTrailingChrome(doc);
|
|
143
|
+
return mapResult(new Defuddle(doc, {
|
|
144
|
+
url,
|
|
145
|
+
separateMarkdown: true
|
|
146
|
+
}).parse());
|
|
147
|
+
}
|
|
148
|
+
const { Defuddle: DefuddleNode } = await import("defuddle/node");
|
|
149
|
+
return mapResult(await DefuddleNode(html, url, {
|
|
150
|
+
separateMarkdown: true
|
|
151
|
+
}));
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/operations/sources/article.ts
|
|
155
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
156
|
+
var MAX_RESPONSE_BYTES = 2e6;
|
|
157
|
+
var MAX_RESPONSE_BYTES_HEADER = 5e6;
|
|
158
|
+
var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
|
|
159
|
+
"localhost",
|
|
160
|
+
"127.0.0.1",
|
|
161
|
+
"0.0.0.0",
|
|
162
|
+
"::1",
|
|
163
|
+
"169.254.169.254",
|
|
164
|
+
"metadata.google.internal"
|
|
165
|
+
]);
|
|
166
|
+
var validateUrl = (link) => {
|
|
167
|
+
const url = new URL(link);
|
|
168
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
169
|
+
throw new Error(`Unsupported protocol: ${url.protocol}`);
|
|
170
|
+
}
|
|
171
|
+
const host = url.hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
172
|
+
if (BLOCKED_HOSTS.has(host)) {
|
|
173
|
+
throw new Error(`Blocked host: ${host}`);
|
|
174
|
+
}
|
|
175
|
+
return url;
|
|
176
|
+
};
|
|
177
|
+
var readCapped = async (response, limit) => {
|
|
178
|
+
const reader = response.body?.getReader();
|
|
179
|
+
if (!reader) {
|
|
180
|
+
throw new Error("Response body stream unavailable.");
|
|
181
|
+
}
|
|
182
|
+
const decoder = new TextDecoder("utf-8");
|
|
183
|
+
let received = 0;
|
|
184
|
+
let out = "";
|
|
185
|
+
while (received < limit) {
|
|
186
|
+
const { value, done } = await reader.read();
|
|
187
|
+
if (done) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
if (value) {
|
|
191
|
+
received += value.byteLength;
|
|
192
|
+
out += decoder.decode(value, {
|
|
193
|
+
stream: true
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
await reader.cancel();
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
return (out + decoder.decode()).slice(0, limit);
|
|
202
|
+
};
|
|
203
|
+
var fetchArticle = async (link, options = {}) => {
|
|
204
|
+
try {
|
|
205
|
+
const url = validateUrl(link);
|
|
206
|
+
const fetchTarget = applyCorsProxy(url.toString(), options.corsProxy);
|
|
207
|
+
const response = await fetch(fetchTarget, {
|
|
208
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
209
|
+
redirect: "follow"
|
|
210
|
+
});
|
|
211
|
+
if (!response.ok) {
|
|
212
|
+
throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);
|
|
213
|
+
}
|
|
214
|
+
const contentLength = response.headers.get("content-length");
|
|
215
|
+
if (contentLength && Number(contentLength) > MAX_RESPONSE_BYTES_HEADER) {
|
|
216
|
+
throw new Error(`Response too large: ${contentLength} bytes`);
|
|
217
|
+
}
|
|
218
|
+
const html = await readCapped(response, MAX_RESPONSE_BYTES);
|
|
219
|
+
const article = await extractArticle(html, url.toString());
|
|
220
|
+
return {
|
|
221
|
+
text: article.markdown,
|
|
222
|
+
imageUrls: article.imageUrls
|
|
223
|
+
};
|
|
224
|
+
} catch (error) {
|
|
225
|
+
throw new Error(`Failed to fetch article: ${String(error)}`, {
|
|
226
|
+
cause: error instanceof Error ? error : void 0
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// src/operations/sources/rss.ts
|
|
232
|
+
import * as FetchHttpClient from "@effect/platform/FetchHttpClient";
|
|
233
|
+
import * as Effect2 from "effect/Effect";
|
|
234
|
+
import { XMLParser } from "fast-xml-parser";
|
|
235
|
+
import { normalizeText } from "@dxos/markdown";
|
|
236
|
+
import { Subscription } from "#types";
|
|
237
|
+
|
|
238
|
+
// src/operations/sources/feed-fetcher.ts
|
|
239
|
+
import * as Data from "effect/Data";
|
|
240
|
+
var FeedFetchError = class extends Data.TaggedError("FeedFetchError") {
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/operations/sources/http.ts
|
|
244
|
+
import * as HttpClient from "@effect/platform/HttpClient";
|
|
245
|
+
import * as HttpClientRequest from "@effect/platform/HttpClientRequest";
|
|
246
|
+
import * as HttpClientResponse from "@effect/platform/HttpClientResponse";
|
|
247
|
+
import * as Effect from "effect/Effect";
|
|
248
|
+
import * as Schedule from "effect/Schedule";
|
|
249
|
+
var retryPolicy = Schedule.exponential("500 millis").pipe(Schedule.compose(Schedule.recurs(2)));
|
|
250
|
+
var getJson = (schema, url, proxy) => HttpClientRequest.get(applyCorsProxy(url, proxy)).pipe(HttpClient.execute, Effect.flatMap(HttpClientResponse.schemaBodyJson(schema)), Effect.timeout("10 seconds"), Effect.retry(retryPolicy), Effect.scoped, Effect.mapError((cause) => new FeedFetchError({
|
|
251
|
+
message: `Fetch failed: ${url}`,
|
|
252
|
+
cause
|
|
253
|
+
})));
|
|
254
|
+
var getText = (url, proxy) => HttpClientRequest.get(applyCorsProxy(url, proxy)).pipe(HttpClient.execute, Effect.flatMap((response) => response.text), Effect.timeout("10 seconds"), Effect.retry(retryPolicy), Effect.scoped, Effect.mapError((cause) => new FeedFetchError({
|
|
255
|
+
message: `Fetch failed: ${url}`,
|
|
256
|
+
cause
|
|
257
|
+
})));
|
|
258
|
+
|
|
259
|
+
// src/operations/sources/rss.ts
|
|
260
|
+
var stripCdata = (value) => value.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, "$1");
|
|
261
|
+
var text = (value) => {
|
|
262
|
+
if (value == null) {
|
|
263
|
+
return void 0;
|
|
264
|
+
}
|
|
265
|
+
if (typeof value === "string") {
|
|
266
|
+
return decodeEntities(stripCdata(value));
|
|
267
|
+
}
|
|
268
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
269
|
+
return String(value);
|
|
270
|
+
}
|
|
271
|
+
if (typeof value === "object") {
|
|
272
|
+
const t = value["#text"];
|
|
273
|
+
if (typeof t === "string") {
|
|
274
|
+
return decodeEntities(stripCdata(t));
|
|
275
|
+
}
|
|
276
|
+
if (typeof t === "number" || typeof t === "boolean") {
|
|
277
|
+
return String(t);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return void 0;
|
|
281
|
+
};
|
|
282
|
+
var markdown = (value) => value != null ? normalizeText(value) : void 0;
|
|
283
|
+
var fetchRss = (url, options) => Effect2.gen(function* () {
|
|
284
|
+
const xml = yield* getText(url, options?.corsProxy);
|
|
285
|
+
return yield* Effect2.try({
|
|
286
|
+
try: () => parseFeed(url, xml),
|
|
287
|
+
catch: (cause) => new FeedFetchError({
|
|
288
|
+
message: `Unrecognized feed format: ${url}`,
|
|
289
|
+
cause
|
|
290
|
+
})
|
|
291
|
+
});
|
|
292
|
+
}).pipe(Effect2.provide(FetchHttpClient.layer));
|
|
293
|
+
var parseFeed = (url, xml) => {
|
|
294
|
+
const parser = new XMLParser({
|
|
295
|
+
ignoreAttributes: false,
|
|
296
|
+
attributeNamePrefix: "@_",
|
|
297
|
+
// RSS/Atom feeds frequently embed HTML (sometimes un-escaped, without CDATA) in content fields,
|
|
298
|
+
// which can blow past fast-xml-parser's default 100-tag nesting cap.
|
|
299
|
+
maxNestedTags: 1e4,
|
|
300
|
+
// Treat known HTML-bearing fields as opaque text so embedded markup isn't parsed as XML.
|
|
301
|
+
stopNodes: [
|
|
302
|
+
"*.description",
|
|
303
|
+
"*.summary",
|
|
304
|
+
"*.content",
|
|
305
|
+
"*.content:encoded"
|
|
306
|
+
]
|
|
307
|
+
});
|
|
308
|
+
const parsed = parser.parse(xml);
|
|
309
|
+
const channel = parsed.rss?.channel ?? parsed.feed;
|
|
310
|
+
if (!channel) {
|
|
311
|
+
throw new Error("Unrecognized feed format");
|
|
312
|
+
}
|
|
313
|
+
const isAtom = !parsed.rss;
|
|
314
|
+
const feedName = text(channel.title) ?? "";
|
|
315
|
+
const feedDescription = markdown(text(isAtom ? channel.subtitle : channel.description)) ?? "";
|
|
316
|
+
const items = (isAtom ? channel.entry : channel.item) ?? [];
|
|
317
|
+
const itemList = Array.isArray(items) ? items : [
|
|
318
|
+
items
|
|
319
|
+
];
|
|
320
|
+
const posts = itemList.map((item) => {
|
|
321
|
+
const link = isAtom ? (Array.isArray(item.link) ? item.link.find((l) => l["@_rel"] === "alternate")?.["@_href"] : item.link?.["@_href"] ?? text(item.link)) ?? "" : text(item.link) ?? "";
|
|
322
|
+
const author = isAtom ? text(item.author?.name) ?? text(item.author) : text(item["dc:creator"]) ?? text(item.author);
|
|
323
|
+
const description = markdown(text(item.description));
|
|
324
|
+
const content = isAtom ? markdown(text(item.summary)) ?? markdown(text(item.content)) : markdown(text(item["content:encoded"]));
|
|
325
|
+
return Subscription.makePost({
|
|
326
|
+
title: text(item.title),
|
|
327
|
+
link,
|
|
328
|
+
description,
|
|
329
|
+
content,
|
|
330
|
+
author,
|
|
331
|
+
published: text(item.pubDate) ?? text(item.published) ?? text(item.updated),
|
|
332
|
+
guid: (isAtom ? text(item.id) : text(item.guid)) ?? link
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
const feed = Subscription.makeSubscription({
|
|
336
|
+
name: feedName,
|
|
337
|
+
url,
|
|
338
|
+
description: feedDescription
|
|
339
|
+
});
|
|
340
|
+
return {
|
|
341
|
+
feed,
|
|
342
|
+
posts
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// src/operations/sources/standard-site.ts
|
|
347
|
+
import * as FetchHttpClient2 from "@effect/platform/FetchHttpClient";
|
|
348
|
+
import * as Effect3 from "effect/Effect";
|
|
349
|
+
import * as Schema from "effect/Schema";
|
|
350
|
+
import { Subscription as Subscription2 } from "#types";
|
|
351
|
+
var BSKY_PUBLIC_API = "https://public.api.bsky.app/xrpc";
|
|
352
|
+
var PLC_DIRECTORY = "https://plc.directory";
|
|
353
|
+
var DOCUMENT_COLLECTION = "site.standard.document";
|
|
354
|
+
var MARKDOWN_CONTENT_TYPE = "site.standard.content.markdown";
|
|
355
|
+
var endpoints = {
|
|
356
|
+
resolveHandle: (handle) => `${BSKY_PUBLIC_API}/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(handle)}`,
|
|
357
|
+
getProfile: (actor) => `${BSKY_PUBLIC_API}/app.bsky.actor.getProfile?actor=${encodeURIComponent(actor)}`,
|
|
358
|
+
searchActors: (query, limit) => `${BSKY_PUBLIC_API}/app.bsky.actor.searchActorsTypeahead?q=${encodeURIComponent(query)}&limit=${limit}`,
|
|
359
|
+
plcDoc: (did) => `${PLC_DIRECTORY}/${did}`,
|
|
360
|
+
listRecords: (pds, did, collection, limit) => `${pds}/xrpc/com.atproto.repo.listRecords?repo=${encodeURIComponent(did)}&collection=${encodeURIComponent(collection)}&limit=${limit}`,
|
|
361
|
+
getRecord: (pds, did, collection, rkey) => `${pds}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(did)}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent(rkey)}`
|
|
362
|
+
};
|
|
363
|
+
var parseStandardSiteActor = (url) => {
|
|
364
|
+
const match = url.match(/bsky\.app\/profile\/([^/?#]+)/);
|
|
365
|
+
if (match) {
|
|
366
|
+
return match[1];
|
|
367
|
+
}
|
|
368
|
+
return url.replace(/^@/, "").trim();
|
|
369
|
+
};
|
|
370
|
+
var listStandardSitePublications = (actorOrUrl, options) => Effect3.gen(function* () {
|
|
371
|
+
const proxy = options?.corsProxy;
|
|
372
|
+
const actor = parseStandardSiteActor(actorOrUrl);
|
|
373
|
+
const did = yield* resolveDid(actor, proxy);
|
|
374
|
+
const pds = yield* resolvePds(did, proxy);
|
|
375
|
+
const records = yield* listDocuments(pds, did, proxy);
|
|
376
|
+
const sites = distinct(records.map((record) => record.value.site).filter(isString));
|
|
377
|
+
return yield* Effect3.forEach(sites, (site) => resolvePublication(site, proxy).pipe(Effect3.catchAll(() => Effect3.succeed({
|
|
378
|
+
site
|
|
379
|
+
}))), {
|
|
380
|
+
concurrency: "unbounded"
|
|
381
|
+
});
|
|
382
|
+
}).pipe(Effect3.provide(FetchHttpClient2.layer));
|
|
383
|
+
var searchStandardSiteHandles = (query, options) => query.trim().length === 0 ? Effect3.succeed([]) : getJson(SearchActorsResponse, endpoints.searchActors(query.trim(), 8), options?.corsProxy).pipe(Effect3.map((response) => (response.actors ?? []).map((actor) => ({
|
|
384
|
+
handle: actor.handle,
|
|
385
|
+
displayName: actor.displayName
|
|
386
|
+
}))), Effect3.orElseSucceed(() => []), Effect3.provide(FetchHttpClient2.layer));
|
|
387
|
+
var fetchStandardSite = (url, options) => Effect3.gen(function* () {
|
|
388
|
+
const proxy = options?.corsProxy;
|
|
389
|
+
const did = yield* resolveDidFromSite(url, proxy);
|
|
390
|
+
const pds = yield* resolvePds(did, proxy);
|
|
391
|
+
const allRecords = yield* listDocuments(pds, did, proxy);
|
|
392
|
+
const records = allRecords.filter((record) => record.value.site === url);
|
|
393
|
+
const profile = yield* fetchProfile(did, proxy);
|
|
394
|
+
const authorName = profile?.displayName ?? profile?.handle ?? did;
|
|
395
|
+
const publication = yield* resolvePublication(url, proxy).pipe(Effect3.catchAll(() => Effect3.succeed({
|
|
396
|
+
site: url
|
|
397
|
+
})));
|
|
398
|
+
const posts = records.map((record) => {
|
|
399
|
+
const value = record.value;
|
|
400
|
+
const content = value.content?.$type === MARKDOWN_CONTENT_TYPE ? value.content.text : void 0;
|
|
401
|
+
const description = value.description ?? (value.textContent ? makeSnippet(value.textContent) : void 0);
|
|
402
|
+
return Subscription2.makePost({
|
|
403
|
+
title: value.title,
|
|
404
|
+
link: joinUrl(publication.url, value.path),
|
|
405
|
+
description,
|
|
406
|
+
content,
|
|
407
|
+
author: authorName,
|
|
408
|
+
published: value.publishedAt,
|
|
409
|
+
// The record's AT-URI is the stable dedup key (see `sync-feed.ts` `postKey`).
|
|
410
|
+
guid: record.uri
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
posts.sort((postA, postB) => (postB.published ?? "").localeCompare(postA.published ?? ""));
|
|
414
|
+
const feed = Subscription2.makeSubscription({
|
|
415
|
+
name: publication.name ?? authorName,
|
|
416
|
+
url,
|
|
417
|
+
description: profile?.description ?? `Standard.site articles from @${profile?.handle ?? did}`,
|
|
418
|
+
iconUrl: profile?.avatar,
|
|
419
|
+
type: "standard-site"
|
|
420
|
+
});
|
|
421
|
+
return {
|
|
422
|
+
feed,
|
|
423
|
+
posts
|
|
424
|
+
};
|
|
425
|
+
}).pipe(Effect3.provide(FetchHttpClient2.layer));
|
|
426
|
+
var ResolveHandleResponse = Schema.Struct({
|
|
427
|
+
did: Schema.optional(Schema.String)
|
|
428
|
+
});
|
|
429
|
+
var SearchActorsResponse = Schema.Struct({
|
|
430
|
+
actors: Schema.optional(Schema.Array(Schema.Struct({
|
|
431
|
+
handle: Schema.String,
|
|
432
|
+
displayName: Schema.optional(Schema.String)
|
|
433
|
+
})))
|
|
434
|
+
});
|
|
435
|
+
var DidDocument = Schema.Struct({
|
|
436
|
+
service: Schema.optional(Schema.Array(Schema.Struct({
|
|
437
|
+
id: Schema.optional(Schema.String),
|
|
438
|
+
type: Schema.optional(Schema.String),
|
|
439
|
+
serviceEndpoint: Schema.optional(Schema.String)
|
|
440
|
+
})))
|
|
441
|
+
});
|
|
442
|
+
var Profile = Schema.Struct({
|
|
443
|
+
handle: Schema.optional(Schema.String),
|
|
444
|
+
displayName: Schema.optional(Schema.String),
|
|
445
|
+
avatar: Schema.optional(Schema.String),
|
|
446
|
+
description: Schema.optional(Schema.String)
|
|
447
|
+
});
|
|
448
|
+
var StandardSiteDocument = Schema.Struct({
|
|
449
|
+
site: Schema.optional(Schema.String),
|
|
450
|
+
title: Schema.optional(Schema.String),
|
|
451
|
+
publishedAt: Schema.optional(Schema.String),
|
|
452
|
+
path: Schema.optional(Schema.String),
|
|
453
|
+
description: Schema.optional(Schema.String),
|
|
454
|
+
content: Schema.optional(Schema.Struct({
|
|
455
|
+
$type: Schema.optional(Schema.String),
|
|
456
|
+
text: Schema.optional(Schema.String)
|
|
457
|
+
})),
|
|
458
|
+
textContent: Schema.optional(Schema.String)
|
|
459
|
+
});
|
|
460
|
+
var ListRecordsResponse = Schema.Struct({
|
|
461
|
+
records: Schema.optional(Schema.Array(Schema.Struct({
|
|
462
|
+
uri: Schema.String,
|
|
463
|
+
value: StandardSiteDocument
|
|
464
|
+
}))),
|
|
465
|
+
cursor: Schema.optional(Schema.String)
|
|
466
|
+
});
|
|
467
|
+
var PublicationRecord = Schema.Struct({
|
|
468
|
+
value: Schema.optional(Schema.Struct({
|
|
469
|
+
url: Schema.optional(Schema.String),
|
|
470
|
+
name: Schema.optional(Schema.String)
|
|
471
|
+
}))
|
|
472
|
+
});
|
|
473
|
+
var resolveDidFromSite = (site, proxy) => {
|
|
474
|
+
if (site.startsWith("at://")) {
|
|
475
|
+
const parsed = parseAtUri(site);
|
|
476
|
+
return parsed ? Effect3.succeed(parsed.did) : Effect3.fail(new FeedFetchError({
|
|
477
|
+
message: `Malformed at:// site reference: ${site}`
|
|
478
|
+
}));
|
|
479
|
+
}
|
|
480
|
+
if (site.startsWith("https://")) {
|
|
481
|
+
const { hostname } = new URL(site);
|
|
482
|
+
return getJson(Schema.Struct({
|
|
483
|
+
did: Schema.optional(Schema.String)
|
|
484
|
+
}), `https://${hostname}/.well-known/atproto-did`, proxy).pipe(Effect3.flatMap((result) => result.did ? Effect3.succeed(result.did) : Effect3.fail(new FeedFetchError({
|
|
485
|
+
message: `No atproto DID found at ${hostname}/.well-known/atproto-did`
|
|
486
|
+
}))));
|
|
487
|
+
}
|
|
488
|
+
return Effect3.fail(new FeedFetchError({
|
|
489
|
+
message: `Cannot resolve DID from site reference: ${site}`
|
|
490
|
+
}));
|
|
491
|
+
};
|
|
492
|
+
var resolveDid = (actor, proxy) => actor.startsWith("did:") ? Effect3.succeed(actor) : getJson(ResolveHandleResponse, endpoints.resolveHandle(actor), proxy).pipe(Effect3.flatMap((resolved) => resolved.did ? Effect3.succeed(resolved.did) : Effect3.fail(new FeedFetchError({
|
|
493
|
+
message: `Could not resolve handle to DID: ${actor}`
|
|
494
|
+
}))));
|
|
495
|
+
var resolvePds = (did, proxy) => {
|
|
496
|
+
if (did.startsWith("did:plc:")) {
|
|
497
|
+
return getJson(DidDocument, endpoints.plcDoc(did), proxy).pipe(Effect3.flatMap((doc) => extractPds(doc, did)));
|
|
498
|
+
}
|
|
499
|
+
if (did.startsWith("did:web:")) {
|
|
500
|
+
const [host, ...segments] = did.slice("did:web:".length).split(":").map((segment) => decodeURIComponent(segment));
|
|
501
|
+
if (!host) {
|
|
502
|
+
return Effect3.fail(new FeedFetchError({
|
|
503
|
+
message: `Invalid did:web identifier: ${did}`
|
|
504
|
+
}));
|
|
505
|
+
}
|
|
506
|
+
const path = segments.length > 0 ? `/${segments.join("/")}/did.json` : "/.well-known/did.json";
|
|
507
|
+
return getJson(DidDocument, `https://${host}${path}`, proxy).pipe(Effect3.flatMap((doc) => extractPds(doc, did)));
|
|
508
|
+
}
|
|
509
|
+
return Effect3.fail(new FeedFetchError({
|
|
510
|
+
message: `Unsupported DID method: ${did}`
|
|
511
|
+
}));
|
|
512
|
+
};
|
|
513
|
+
var extractPds = (doc, did) => {
|
|
514
|
+
const service = doc.service?.find((entry) => entry.id === "#atproto_pds" || entry.type === "AtprotoPersonalDataServer");
|
|
515
|
+
const endpoint = service?.serviceEndpoint;
|
|
516
|
+
return typeof endpoint === "string" && endpoint.length > 0 ? Effect3.succeed(endpoint.replace(/\/$/, "")) : Effect3.fail(new FeedFetchError({
|
|
517
|
+
message: `No PDS endpoint found for DID: ${did}`
|
|
518
|
+
}));
|
|
519
|
+
};
|
|
520
|
+
var listDocuments = (pds, did, proxy) => Effect3.gen(function* () {
|
|
521
|
+
const all = [];
|
|
522
|
+
let cursor;
|
|
523
|
+
do {
|
|
524
|
+
const url = endpoints.listRecords(pds, did, DOCUMENT_COLLECTION, 100) + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : "");
|
|
525
|
+
const page = yield* getJson(ListRecordsResponse, url, proxy);
|
|
526
|
+
all.push(...page.records ?? []);
|
|
527
|
+
cursor = page.cursor;
|
|
528
|
+
} while (cursor);
|
|
529
|
+
return all;
|
|
530
|
+
});
|
|
531
|
+
var fetchProfile = (actor, proxy) => getJson(Profile, endpoints.getProfile(actor), proxy).pipe(Effect3.catchAll(() => Effect3.succeed(void 0)));
|
|
532
|
+
var resolvePublication = (site, proxy) => {
|
|
533
|
+
if (site.startsWith("http")) {
|
|
534
|
+
return Effect3.succeed({
|
|
535
|
+
site,
|
|
536
|
+
url: site.replace(/\/$/, "")
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
if (site.startsWith("at://")) {
|
|
540
|
+
const parsed = parseAtUri(site);
|
|
541
|
+
if (!parsed) {
|
|
542
|
+
return Effect3.succeed({
|
|
543
|
+
site
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
return Effect3.gen(function* () {
|
|
547
|
+
const pds = yield* resolvePds(parsed.did, proxy);
|
|
548
|
+
const record = yield* getJson(PublicationRecord, endpoints.getRecord(pds, parsed.did, parsed.collection, parsed.rkey), proxy);
|
|
549
|
+
const value = record.value ?? {};
|
|
550
|
+
return {
|
|
551
|
+
site,
|
|
552
|
+
url: value.url ? value.url.replace(/\/$/, "") : void 0,
|
|
553
|
+
name: value.name
|
|
554
|
+
};
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
return Effect3.succeed({
|
|
558
|
+
site
|
|
559
|
+
});
|
|
560
|
+
};
|
|
561
|
+
var parseAtUri = (uri) => {
|
|
562
|
+
const match = uri.match(/^at:\/\/([^/]+)\/([^/]+)\/([^/]+)$/);
|
|
563
|
+
return match ? {
|
|
564
|
+
did: match[1],
|
|
565
|
+
collection: match[2],
|
|
566
|
+
rkey: match[3]
|
|
567
|
+
} : void 0;
|
|
568
|
+
};
|
|
569
|
+
var joinUrl = (base, path) => {
|
|
570
|
+
if (!base) {
|
|
571
|
+
return void 0;
|
|
572
|
+
}
|
|
573
|
+
if (!path) {
|
|
574
|
+
return base;
|
|
575
|
+
}
|
|
576
|
+
return `${base}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
577
|
+
};
|
|
578
|
+
var isString = (value) => typeof value === "string";
|
|
579
|
+
var distinct = (values) => [
|
|
580
|
+
...new Set(values)
|
|
581
|
+
];
|
|
582
|
+
|
|
583
|
+
export {
|
|
584
|
+
browserCorsProxy,
|
|
585
|
+
fetchArticle,
|
|
586
|
+
fetchRss,
|
|
587
|
+
listStandardSitePublications,
|
|
588
|
+
searchStandardSiteHandles,
|
|
589
|
+
fetchStandardSite
|
|
590
|
+
};
|
|
591
|
+
//# sourceMappingURL=chunk-AFPBWBTK.mjs.map
|