Skip to content

Commit

Permalink
chore: release [email protected]
Browse files Browse the repository at this point in the history
  • Loading branch information
lin-stephanie committed Jan 1, 2025
1 parent 934ca3c commit bdaeced
Show file tree
Hide file tree
Showing 10 changed files with 3,525 additions and 14 deletions.
7 changes: 7 additions & 0 deletions .changeset/tiny-swans-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"astro-loader-bluesky-posts": major
---

Support loading Bluesky posts using [AT-URI](https://atproto.com/specs/at-uri-scheme)
- Customizable HTML generation for posts (e.g., render posts with `<Content />` using `render(entry)`)
- Configurable thread loading and recursive filtering of the post author's replies
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Currently available loaders (see individual READMEs for details):
- [astro-loader-github-releases](https://github.com/lin-stephanie/astro-loaders/tree/main/packages/astro-loader-github-releases): Loads GitHub releases from commits or repositories.
- [astro-loader-github-prs](https://github.com/lin-stephanie/astro-loaders/tree/main/packages/astro-loader-github-prs): Loads GitHub pull requests with a search query.
- [astro-loader-tweets](https://github.com/lin-stephanie/astro-loaders/tree/main/packages/astro-loader-tweets): Loads tweets by ID.
- [astro-loader-bluesky-posts](https://github.com/lin-stephanie/astro-loaders/tree/main/packages/astro-loader-bluesky-posts): Loads Bluesky posts and threads using AT-URI.

## Resources

Expand Down
105 changes: 105 additions & 0 deletions packages/astro-loader-bluesky-posts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# astro-loader-bluesky-posts

[![version][version-badge]][version-link]
[![jsDocs.io][jsdocs-src]][jsdocs-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]

This package provides a Bluesky posts loader for Astro, utilizing [AT-URI](https://atproto.com/specs/at-uri-scheme) to fetch posts for use in Astro projects. Features include customizable HTML rendering, optional threaded loading, and targeted fetching of author-specific replies.

## Installation

```sh
npm install -D astro-loader-bluesky-posts
```

## Usage

To use the Astro loader, ensure Astro version `^4.14.0 || ^5.0.0`. For `^4.14.0`, enable the [experimental content layer](https://v4.docs.astro.build/en/reference/configuration-reference/#experimentalcontentlayer) in `astro.config.ts`:

```ts
export default defineConfig({
experimental: {
contentLayer: true,
},
})
```

In `src/content/config.ts` (for `^4.14.0`) or `src/content.config.ts` (for `^5.0.0`), import and configure the loader to define a new content collection:

```ts
import { defineCollection } from "astro:content"
import { BlueskyPostsLoader } from "astro-loader-bluesky-posts"

const posts = defineCollection({
loader: BlueskyPostsLoader({
uris: ['at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3lax5zxh7bc2p'],
// Check the configuration below
}),
})

export const collections = { posts }
```

[Query the content collection](https://docs.astro.build/en/guides/content-collections/#querying-collections) like any other Astro content collection to render the loaded posts:

```astro
---
import { getCollection } from "astro:content"
const posts = await getCollection("posts")
// Check the entries' Zod schema for available fields below
---
{
posts.map(async (post) => {
const { Content } = await render(post)
return (
<section>
<Content />
<p>{post.data.indexedAt}</p>
</section>
)
})
}
```

To update the data, trigger a site rebuild, as [the loader fetches data only at build time](https://docs.astro.build/en/reference/content-loader-reference/#object-loaders).

## Configuration

This loader retrieves posts via the Bluesky API [`GET /xrpc/app.bsky.feed.getPosts`](https://docs.bsky.app/docs/api/app-bsky-feed-get-posts) and [`GET /xrpc/app.bsky.feed.getPostThread`](https://docs.bsky.app/docs/api/app-bsky-feed-get-post-thread). Options include:


| Option (* required) | Type (default) | Description |
| ------------------------ | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uris`* | `string[]` | List of post [AT-URIs](https://atproto.com/specs/at-uri-scheme). |
| `linkTextType` | `'domain-path' \| 'display-url'` (default: `'display-url'`) | The type of text to display for links when generating renderable HTML:<br>`'domain-path'`: Displays the link's domain and path.<br>`'display-url'`: Uses the link text as shown in the tweet. |
| `newlineHandling` | `'none' \| 'break' \| 'paragraph'` (default: `'none'`) | The way for processing `\n` when generating renderable HTML:<br>`'none'`: Keep as is.<br>`'break'`: Replace `\n` with `<br>`.<br>`'paragraph'`: Wrap paragraphs with `<p>` while removing standalone `\n`. |
| `fetchThread` | `boolean` (default: `false`) | Whether to fetch the post's thread including replies and parents. |
| `threadDepth` | number (default: `1`) | The depth of the descendant post tree to fetch if fetching the thread. Specifies how many levels of reply depth should be included. |
| `threadParentHeight` | number (default: `1`) | The height of the ancestor post tree to fetch if fetching the thread. Specifies how many levels of parent posts should be included. |
| `fetchOnlyAuthorReplies` | `boolean` (default: `false`) | Whether to include only the replies made by the post author at the specified `threadDepth` if fetching the thread. If `true`, filters replies to include only those authored by the and flatten these replies into a single-level array. |

## Schema

See the [source code](https://github.com/lin-stephanie/astro-loaders/blob/main/packages/astro-loader-bluesky-posts/src/schema.ts) for the Zod schema of loaded entries. Astro automatically applies this schema to generate TypeScript interfaces, enabling autocompletion and type-checking for collection queries.

To [customize the schema](https://docs.astro.build/en/guides/content-collections/#defining-the-collection-schema), ensure compatibility with the loader's built-in Zod schema to prevent errors. For additional fields, consider opening an issue.

## Changelog

See [CHANGELOG.md](https://github.com/lin-stephanie/astro-loaders/blob/main/packages/astro-loader-bluesky-posts/CHANGELOG.md) for the change history of this loader.

## Contribution

If you see any errors or room for improvement, feel free to open an [issues](https://github.com/lin-stephanie/astro-loaders/issues) or [pull request](https://github.com/lin-stephanie/astro-loaders/pulls) . Thank you in advance for contributing! ❤️

<!-- Badges -->

[version-badge]: https://img.shields.io/npm/v/astro-loader-bluesky-posts?label=release&style=flat&colorA=080f12&colorB=f87171
[version-link]: https://www.npmjs.com/package/astro-loader-bluesky-posts
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=f87171
[jsdocs-href]: https://www.jsdocs.io/package/astro-loader-bluesky-posts
[npm-downloads-src]: https://img.shields.io/npm/dm/astro-loader-bluesky-posts?style=flat&colorA=080f12&colorB=f87171
[npm-downloads-href]: https://npmjs.com/package/astro-loader-bluesky-posts

47 changes: 47 additions & 0 deletions packages/astro-loader-bluesky-posts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "astro-loader-bluesky-posts",
"version": "0.0.0",
"description": "Astro loader for loading Bluesky posts and threads using AT-URI.",
"author": "Stephanie Lin <[email protected]>",
"license": "MIT",
"keywords": [
"withastro",
"astro-loader",
"bluesky",
"posts",
"post",
"thread"
],
"repository": {
"type": "git",
"url": "git+https://github.com/lin-stephanie/astro-loaders.git",
"directory": "packages/astro-loader-bluesky-posts"
},
"homepage": "https://github.com/lin-stephanie/astro-loaders/blob/main/packages/astro-loader-bluesky-posts/",
"bugs": "https://github.com/lin-stephanie/astro-loaders/issues",
"type": "module",
"files": [
"dist"
],
"main": "dist/index.js",
"module": "dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"types": "./dist/index.d.ts",
"scripts": {
"dev": "tsup src/index.ts --format esm --dts --watch",
"build": "tsup src/index.ts --format esm --dts --clean --treeshake",
"check": "publint && attw $(pnpm pack) --ignore-rules=cjs-resolves-to-esm",
"prepublishOnly": "pnpm build"
},
"peerDependencies": {
"astro": ">=4.14.0 <6.0.0"
},
"dependencies": {
"@atproto/api": "^0.13.20"
}
}
88 changes: 88 additions & 0 deletions packages/astro-loader-bluesky-posts/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { z } from 'astro/zod'

const defaultConfig = {
urlTextType: 'display-url' as const,
newlineHandling: 'none' as const,
fetchThread: false,
threadDepth: 1,
threadParentHeight: 1,
fetchOnlyAuthorReplies: false,
}

export const BlueskyPostsLoaderConfigSchema = z.object({
/**
* List of post {@link https://atproto.com/specs/at-uri-scheme AT-URIs}
* to return hydrated views for.
*/
uris: z.array(z.string()),

/**
* The type of text to display for links when generating renderable HTML:
* - `'domain-path'`: Displays the link's domain and path.
* - `'display-url'`: Uses the link text as shown in the tweet.
*
* @default 'display-url'
*/
linkTextType: z
.enum(['domain-path', 'display-url'])
.default(defaultConfig.urlTextType),

/**
* The way for processing `\n` when generating renderable HTML:
* - `'none'`: Keep as is.
* - `'break'`: Replace `\n` with `<br>`.
* - `'paragraph'`: Wrap paragraphs with `<p>` while removing standalone `\n`.
*
* @default 'none'
*/
newlineHandling: z
.enum(['none', 'break', 'paragraph'])
.default(defaultConfig.newlineHandling),

/**
* Whether to fetch the post's thread including replies and parents.
*
* @default false
*/
fetchThread: z.boolean().default(defaultConfig.fetchThread),

/**
* The depth of the descendant post tree to fetch if fetching the thread.
* Specifies how many levels of reply depth should be included.
*
* @default 1
*/
threadDepth: z.number().min(0).max(1000).default(defaultConfig.threadDepth),

/**
* The height of the ancestor post tree to fetch if fetching the thread.
* Specifies how many levels of parent posts should be included.
*
* @default 1
*/
threadParentHeight: z
.number()
.min(0)
.max(1000)
.default(defaultConfig.threadParentHeight),

/**
* Whether to include only the replies made by the post author
* at the specified `threadDepth` if fetching the thread.
*
* If `true`, filters replies to include only those authored by the specified DID at any depth
* and flatten these replies into a single-level array.
* The specified `threadParentHeight` will be ignored, and the `parent` field will not be returned.
*
* By default, it fetches all replies without filtering by author and maintains the nested structure.
*
* @default false
*/
fetchOnlyAuthorReplies: z
.boolean()
.default(defaultConfig.fetchOnlyAuthorReplies),
})

export type BlueskyPostsLoaderUserConfig = z.input<
typeof BlueskyPostsLoaderConfigSchema
>
Loading

0 comments on commit bdaeced

Please sign in to comment.