astro-atmosphere-comments 0.4.1 → 0.5.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/CHANGELOG.md +25 -0
- package/README.md +21 -23
- package/components/AtmosphereComments.astro +186 -83
- package/components/AtmosphereReactions.astro +86 -51
- package/components/SignInForm.astro +17 -4
- package/components/atmosphere.css +21 -0
- package/index.mjs +42 -32
- package/lib/client/account.ts +553 -0
- package/lib/client/composer.ts +7 -10
- package/lib/http.ts +28 -0
- package/lib/permissions.ts +108 -0
- package/lib/public-settings.ts +18 -0
- package/lib/thread.ts +36 -6
- package/lib/uris.ts +31 -0
- package/locales/de.json +20 -4
- package/locales/en.json +20 -4
- package/locales/es.json +20 -4
- package/locales/fr.json +20 -4
- package/locales/it.json +20 -4
- package/locales/ja.json +20 -4
- package/locales/nl.json +20 -4
- package/locales/pt.json +20 -4
- package/package.json +2 -7
- package/routes/callback.astro +42 -0
- package/routes/client-metadata.json.ts +3 -2
- package/routes/following.ts +28 -0
- package/routes/identity.ts +69 -0
- package/routes/media.ts +7 -10
- package/routes/post.ts +1 -1
- package/routes/profile.ts +20 -0
- package/routes/richtext.ts +30 -0
- package/routes/thread.ts +23 -3
- package/routes/typeahead.ts +7 -23
- package/virtual.d.ts +5 -0
- package/bin/cli.mjs +0 -31
- package/lib/oauth.ts +0 -110
- package/lib/reader.ts +0 -130
- package/lib/store.ts +0 -46
- package/lib/visitor.ts +0 -42
- package/routes/callback.ts +0 -30
- package/routes/comment.ts +0 -97
- package/routes/delete.ts +0 -41
- package/routes/follow.ts +0 -71
- package/routes/jwks.json.ts +0 -13
- package/routes/login.ts +0 -58
- package/routes/logout.ts +0 -20
- package/routes/me.ts +0 -12
- package/routes/react.ts +0 -48
- package/routes/state.ts +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 (4 November 2026)
|
|
4
|
+
|
|
5
|
+
**Readers' sign-ins now stay in their own browsers.** This changes how the package works, so read "Upgrading" below.
|
|
6
|
+
|
|
7
|
+
- **Browser sign-in:** readers sign in as a browser ("public") OAuth client, with `@atproto/oauth-client-browser`. Their sign-in is kept in their browser's storage, with a key the browser won't let even the page's code read out, and comments, likes, reposts, deletes and follows go from their browser straight to their own account host. Your server never sees a sign-in, sets no cookies and stores nothing, so it has no way to post for anyone. Signing out cancels the sign-in at the reader's host and deletes it from their browser. Account hosts give browser sign-ins a shorter life (Bluesky's last about two weeks).
|
|
8
|
+
- **One approval for everything:** signing in asks for all that readers can do here at once (posting; liking and reposting; deleting their comments; following your accounts), plus hiding comments when the account is one of your own (`allowedAuthors`). Deleting and following were asked for separately before; with the sign-in in the browser, separate trips to the account host only confused readers. Permissions are grouped in `lib/permissions.ts`. Readers whose sign-in lacks a group (one from before it was added) are asked for it when it's first needed, after the page says what it's for, which account, and that their account host may ask them to sign in again first. `SignInForm` takes a `permissions` prop for anything more.
|
|
9
|
+
- **Hide comments:** signed in as the account that posted the announcement, a Hide button under other people's comments hides them here and on Bluesky (the announcement's threadgate, as the Bluesky app does). The first hide asks for that permission. Show them again in the Bluesky app. Fires `atmosphere:hidden` (`detail`: `uri`).
|
|
10
|
+
- **Respecting "logged-out" privacy:** accounts that use Bluesky's "Discourage apps from showing my account to logged-out users" are no longer shown on the page, which is public. Their comments become a short "Not shown here" placeholder (nothing about them reaches the page) with the replies under them kept, and they're left out of the like and repost faces. New wording key `comment.withheld`; style `.atmo-comment__withheld`.
|
|
11
|
+
- **Fewer third parties:** account lookups while signing in go through your server (`/atmosphere/identity`), so readers' browsers contact only their own account host.
|
|
12
|
+
- Under the sign-in button, a line says the sign-in stays in the browser, with a link to your privacy policy if you set `policyUri`.
|
|
13
|
+
- Routes: `login`, `logout`, `me`, `comment`, `react`, `delete`, `follow`, `state` and `jwks.json` are gone. New: `identity`, `profile`, `richtext` (links and mentions in a comment, before it's posted) and `following`; `callback` is now a page; `POST /atmosphere/thread` refreshes a thread after a reader posts. The `typeahead` limits are per address for everyone.
|
|
14
|
+
- The `keygen` command is gone: there's no key.
|
|
15
|
+
- New wording keys (`signIn.access`, `signIn.policy`, `composer.needsPermission`, `comment.hide…`, `comment.deleteElsewhere`, `permission.…`, `callback.signingIn`) in all eight languages; `messages.newPermissions` is gone and `messages.needsPermission` is now general.
|
|
16
|
+
|
|
17
|
+
### Upgrading from 0.4
|
|
18
|
+
|
|
19
|
+
- Remove `ATMOSPHERE_PRIVATE_JWK` and `ATMOSPHERE_DATA_DIR` from your server's environment (and your deploy's secrets), and delete the data folder (default `.data/atmosphere`). The sign-ins in it can't be used without it: their tokens only work with keys kept in those files.
|
|
20
|
+
- **Readers will need to sign in again.** Their old sign-ins (made with the server key) may still be listed at their account host until they expire; they can remove them there.
|
|
21
|
+
- If you set a Content Security Policy, allow `connect-src` to readers' account hosts (any `https:` address), since the browser now talks to them directly.
|
|
22
|
+
- The site no longer needs a disk that persists.
|
|
23
|
+
|
|
24
|
+
## 0.4.2 (4 November 2026)
|
|
25
|
+
|
|
26
|
+
- Links open in a new tab: those in the sign-in form, "Reply on Bluesky instead", the credit, and the thread's names, dates, faces and links in comments, so readers don't lose their place (and a half-written comment).
|
|
27
|
+
|
|
3
28
|
## 0.4.1 (4 November 2026)
|
|
4
29
|
|
|
5
30
|
- Fixed: the sign-in and reply overlays of `AtmosphereReactions` showed at the bottom of the page instead of staying hidden until opened (the shared stylesheet made every `.atmo` element a block, dialogs included).
|
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Under each post, readers type their Bluesky handle (or that of any other [Atmosp
|
|
|
10
10
|
- **@mention** people, with suggestions as they type;
|
|
11
11
|
- **delete** their own comments.
|
|
12
12
|
|
|
13
|
+
And signed in as one of your own accounts, you can **hide** comments under your posts, here and on Bluesky.
|
|
14
|
+
|
|
13
15
|
Everything they post is written to **their own account**, as ordinary Bluesky posts, likes and reposts: comments are replies to your post's announcement on Bluesky. They can delete them in any Bluesky app, and people who prefer the app can reply there instead; it all shows up on your page the same way.
|
|
14
16
|
|
|
15
17
|
The component also **shows the thread**: who liked and reposted your post, and the comments, nested, with their own Reply, Like and Repost.
|
|
@@ -20,17 +22,17 @@ See it on [saltedlolly.com](https://saltedlolly.com/2005/07/13/summer-jam-party-
|
|
|
20
22
|
|
|
21
23
|
1. You announce each post on Bluesky (a post linking to it). That post's thread is the comment section.
|
|
22
24
|
2. A reader signs in with **AT Protocol OAuth, straight to their own account host** (Bluesky's, for most people), which asks them to approve your site, named by its address (example.com). There is no third-party login service in between, and your site never sees a password.
|
|
23
|
-
3.
|
|
24
|
-
4. Your
|
|
25
|
+
3. **The sign-in stays in the reader's browser.** Your server never sees it: comments, likes and reposts go from the reader's browser straight to their own account host. So your server has no way to post for anyone, a copy of your server's files holds nothing about your readers, and when a reader signs out, the sign-in is cancelled at their host and deleted from their browser. That's it: nothing is left anywhere.
|
|
26
|
+
4. Your site asks, in one approval, only for what readers can do on it: to create posts, to like and repost, to delete their comments and to follow your accounts (and, when one of your own accounts signs in, to hide comments). Each is used only on your posts, the comments under them and your accounts. Readers can see and cancel it all at their account host.
|
|
25
27
|
|
|
26
28
|
Readers who'd rather not sign in can use the **Reply on Bluesky instead** link under the form.
|
|
27
29
|
|
|
28
|
-
Images (avatars, link-card pictures)
|
|
30
|
+
Images (avatars, link-card pictures), account searches (the suggestions under the sign-in box and for @mentions) and account lookups when signing in go through your server, so readers' browsers contact only their own account host, never Bluesky's other servers.
|
|
29
31
|
|
|
30
32
|
## Requirements
|
|
31
33
|
|
|
32
34
|
- **Astro 7** with an on-demand (server) adapter, such as [`@astrojs/node`](https://docs.astro.build/en/guides/integrations-guide/node/). The pages themselves can stay static; the integration adds a few server routes.
|
|
33
|
-
- **Node 20.19 or later
|
|
35
|
+
- **Node 20.19 or later.** Nothing is stored on your server (no sign-ins, no cookies, no files), so no disk or database is needed.
|
|
34
36
|
- A **Bluesky account that announces your posts**. Each post needs its announcement's address, or a [Standard.site](https://standard.site) record that points to it (see below).
|
|
35
37
|
- Your site's **`site`** set in `astro.config`.
|
|
36
38
|
|
|
@@ -64,17 +66,9 @@ export default defineConfig({
|
|
|
64
66
|
|
|
65
67
|
To find an account's DID: `https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=you.bsky.social`.
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```sh
|
|
70
|
-
npx astro-atmosphere-comments keygen
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
This adds `ATMOSPHERE_PRIVATE_JWK` to your `.env` without printing it. Your site signs its requests to readers' account hosts with it; the public half is published at `/atmosphere/jwks.json`, and the site's details for account hosts (its name, logo and permissions) at `/oauth-client-metadata.json`. That second file has to be at your site's root: it's the conventional address, and only then does Bluesky's approval page name your site by its address alone. Set the same variable on your server, keep `.env` out of Git, and keep a backup: **a new key signs every reader out.**
|
|
74
|
-
|
|
75
|
-
On the server, also set `ATMOSPHERE_DATA_DIR` to a folder **outside your deploy folder** (for example `/var/lib/example-com/atmosphere`), so deploys don't sign readers out. It defaults to `.data/atmosphere` in the project.
|
|
69
|
+
The integration also publishes your site's details for account hosts (its name, logo and permissions) at `/oauth-client-metadata.json`. That file has to be at your site's root: it's the conventional address, and only then does Bluesky's approval page name your site by its address alone. There's no key or secret to set up.
|
|
76
70
|
|
|
77
|
-
###
|
|
71
|
+
### 2. Put the component under your posts
|
|
78
72
|
|
|
79
73
|
```astro
|
|
80
74
|
---
|
|
@@ -86,7 +80,7 @@ import AtmosphereComments from "astro-atmosphere-comments/AtmosphereComments.ast
|
|
|
86
80
|
|
|
87
81
|
`post` can be the announcement's **bsky.app address** or its **AT URI**. Leave it out and the component uses the page's **Standard.site** record instead: if your page has `<link rel="site.standard.document" href="at://…">` and that record's `bskyPostRef` points to the announcement (as Standard.site publishers do), it just works. With no announcement to respond to, the component shows nothing (apart from your slot content).
|
|
88
82
|
|
|
89
|
-
###
|
|
83
|
+
### 3. Optional: likes and reposts on your other Bluesky posts
|
|
90
84
|
|
|
91
85
|
If your pages show your Bluesky posts elsewhere (a "latest posts" feed on your homepage, say), readers can like and repost them there too. Put `AtmosphereReactions` once in your layout, and mark each post's element:
|
|
92
86
|
|
|
@@ -109,7 +103,7 @@ import AtmosphereReactions from "astro-atmosphere-comments/AtmosphereReactions.a
|
|
|
109
103
|
|
|
110
104
|
Each marked post gets a row of icons: Reply, Repost, Quote and Like, with counts for Repost and Like. Readers already signed in on your site like and repost straight away, and Reply and Quote open the comment box in an overlay (with the quote preview); what they post goes to Bluesky, not your page, and the overlay says so with a link to it. Anyone else is offered the sign-in form in an overlay when they press Like or Repost (their like or repost is done when they come back), and Reply and Quote open the post on Bluesky. It works with posts from loaders such as [`@ascorbic/bluesky-loader`](https://www.npmjs.com/package/@ascorbic/bluesky-loader) or embeds such as [`@astro-community/astro-embed-bluesky`](https://www.npmjs.com/package/@astro-community/astro-embed-bluesky) (wrap the embed in the marked element). Only posts by your `allowedAuthors` can be liked or reposted through your site.
|
|
111
105
|
|
|
112
|
-
A "follow me" link can become a **Follow** button for signed-in readers: mark it with the account's DID and handle. It shows "Following" once they do (a second press unfollows, as on Bluesky).
|
|
106
|
+
A "follow me" link can become a **Follow** button for signed-in readers: mark it with the account's DID and handle. It shows "Following" once they do (a second press unfollows, as on Bluesky). Only your `allowedAuthors` can be followed through your site, and the account's owner (who can't follow themselves) keeps the plain link.
|
|
113
107
|
|
|
114
108
|
```astro
|
|
115
109
|
<a href="https://bsky.app/profile/you.bsky.social"
|
|
@@ -130,7 +124,7 @@ Run the dev server on `127.0.0.1` and open the site there, not at `localhost`:
|
|
|
130
124
|
npx astro dev --host 127.0.0.1
|
|
131
125
|
```
|
|
132
126
|
|
|
133
|
-
Locally the integration uses the protocol's development mode, so
|
|
127
|
+
Locally the integration uses the protocol's development mode, so it works without a public address. Bluesky's approval screen will say a development app is asking, and sign-ins last only about a day; that's expected.
|
|
134
128
|
|
|
135
129
|
## Options
|
|
136
130
|
|
|
@@ -139,7 +133,7 @@ Locally the integration uses the protocol's development mode, so no key is neede
|
|
|
139
133
|
| `clientName` | yes | Your site's name, given to readers' account hosts. (Bluesky's approval page shows your site's address instead, unless Bluesky has marked your site as trusted.) |
|
|
140
134
|
| `allowedAuthors` | yes | DIDs of the accounts whose posts can be commented on through your site. Comments from these accounts get the Author badge. |
|
|
141
135
|
| `logoUri` | | A square logo for the sign-in screen (absolute `https://` address). |
|
|
142
|
-
| `policyUri`, `tosUri` | | Your privacy policy and terms, shown on the sign-in screen. |
|
|
136
|
+
| `policyUri`, `tosUri` | | Your privacy policy and terms, shown on the sign-in screen. The privacy policy is also linked under the sign-in form. |
|
|
143
137
|
| `hidden` | | Comments never to show: bsky.app post or profile addresses, AT URIs, handles or DIDs. Replies you hide in the Bluesky app, and posts with Bluesky's moderation labels (spam and so on), are left out anyway. |
|
|
144
138
|
| `base` | | Where the integration's routes live. Default `/atmosphere`. |
|
|
145
139
|
| `locale` | | The language of the wording, such as `"fr"` or `"pt-BR"` (see Languages). |
|
|
@@ -207,17 +201,21 @@ The component fires (bubbling):
|
|
|
207
201
|
- `atmosphere:commented` after a comment, reply or quote is posted (`detail`: `uri`, `url`, `text`, `author`, `createdAt`, `quote`, `parent`);
|
|
208
202
|
- `atmosphere:reacted` after a like or repost of the post, or undoing one (`detail`: `kind`, `on`, `author`).
|
|
209
203
|
- `atmosphere:deleted` after a reader deletes one of their comments (`detail`: `uri`).
|
|
204
|
+
- `atmosphere:hidden` after the announcement's author hides a comment (`detail`: `uri`).
|
|
210
205
|
|
|
211
206
|
## Security and privacy
|
|
212
207
|
|
|
213
|
-
- **
|
|
214
|
-
- **What
|
|
215
|
-
- **
|
|
216
|
-
-
|
|
208
|
+
- **Readers' sign-ins stay in their browsers.** The OAuth library (`@atproto/oauth-client-browser`) keeps the tokens in the browser's storage, together with a key the browser makes and won't let even the page's own code read out; the tokens only work with that key. Your server never receives them, sets no cookies and stores nothing about readers. Signing out cancels the sign-in at the reader's account host and deletes it from the browser.
|
|
209
|
+
- **What that does and doesn't promise.** Your server can't act for anyone, ever. While a reader has your page open, though, your page's code can use their sign-in, as with any web app they sign in to, so the code that runs matters: it's this package's open source code, and comments are only ever shown as plain text (links, @mentions and #hashtags become links; nothing is rendered as HTML). A [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) on your site adds a second line of defence.
|
|
210
|
+
- **What's checked before anything is sent** (by the browser code, `lib/client/account.ts`): only your announcements and the comments under them can be replied to, liked, reposted or quoted; only a reader's own replies under your announcements can be deleted; only your `allowedAuthors` can be followed; only an announcement's author can hide comments under it.
|
|
211
|
+
- **What your server does:** it shows the threads, looks up accounts and suggestions, finds the links and mentions in a comment before it's posted, and passes on avatars and link pictures it has just shown. None of it needs to know who a reader is. Each route that calls Bluesky is rate-limited per address, with an overall cap; requests that aren't simple reads must come from your own pages (checked by `Origin`). Readers' addresses are used only for those limits, never stored.
|
|
212
|
+
- **Trade-off:** account hosts trust browser sign-ins less than ones kept on a server, so they last less long (Bluesky's currently last about two weeks), and there's no way for a site to sign everyone out at once. For a reader who'd rather not trust your server, that's the point.
|
|
213
|
+
- **People who'd rather not be shown publicly:** Bluesky's setting "Discourage apps from showing my account to logged-out users" is respected, as your page is public. A comment from such an account shows only as "Not shown here…" (no name, picture or words reach the page), the replies under it stay, and the account is left out of the faces of who liked and reposted.
|
|
214
|
+
- **Moderation:** comments appear automatically. Hide one with Hide under it (signed in as the account that posted the announcement) or in the Bluesky app; it disappears here too. Show it again in the Bluesky app. You can also block the account, or add it to `hidden`.
|
|
217
215
|
|
|
218
216
|
## Limitations (for now)
|
|
219
217
|
|
|
220
|
-
- Needs
|
|
218
|
+
- Needs an on-demand (server) adapter, for the few routes above. Serverless hosts should work, as nothing is stored, but haven't been tried.
|
|
221
219
|
- Rate limits are kept in memory, so they apply per server process.
|
|
222
220
|
- Quoting individual comments isn't supported.
|
|
223
221
|
|