astro-atmosphere-comments 0.0.0-stage → 0.1.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 +12 -0
- package/LICENSE +21 -0
- package/README.md +173 -2
- package/assets/LICENSE-atmosphere-account +21 -0
- package/assets/union.svg +15 -0
- package/bin/cli.mjs +31 -0
- package/components/AtmosphereComments.astro +1495 -0
- package/index.d.ts +26 -0
- package/index.mjs +106 -0
- package/lib/avatars.ts +21 -0
- package/lib/http.ts +26 -0
- package/lib/oauth.ts +95 -0
- package/lib/profile.ts +53 -0
- package/lib/quoted.ts +46 -0
- package/lib/reader.ts +115 -0
- package/lib/resolve.ts +58 -0
- package/lib/richtext.ts +61 -0
- package/lib/settings.ts +18 -0
- package/lib/store.ts +46 -0
- package/lib/thread.ts +171 -0
- package/lib/visitor.ts +42 -0
- package/package.json +58 -4
- package/routes/callback.ts +30 -0
- package/routes/client-metadata.json.ts +7 -0
- package/routes/comment.ts +97 -0
- package/routes/jwks.json.ts +13 -0
- package/routes/login.ts +30 -0
- package/routes/logout.ts +20 -0
- package/routes/me.ts +12 -0
- package/routes/media.ts +59 -0
- package/routes/post.ts +33 -0
- package/routes/react.ts +48 -0
- package/routes/state.ts +24 -0
- package/routes/thread.ts +27 -0
- package/routes/typeahead.ts +40 -0
- package/virtual.d.ts +4 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (3 November 2026)
|
|
4
|
+
|
|
5
|
+
First release, as used on [saltedlolly.com](https://saltedlolly.com).
|
|
6
|
+
|
|
7
|
+
- "Respond with your Atmosphere Account": readers sign in with Bluesky or any Atmosphere account (AT Protocol OAuth straight to their own host, no third-party login service).
|
|
8
|
+
- Comment, reply to a comment, like, repost and quote post, all written to the reader's own account; @mention suggestions; a Bluesky-style quote preview.
|
|
9
|
+
- Shows the thread: likes and reposts with faces, and nested comments with their own Reply, Like and Repost.
|
|
10
|
+
- Finds the post's Bluesky announcement from an AT URI, a bsky.app address, or the page's Standard.site record.
|
|
11
|
+
- `npx astro-atmosphere-comments keygen` creates the site's signing key.
|
|
12
|
+
- A small "Powered by Atmosphere Comments for Astro" credit link, which `credit={false}` hides.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Olly Stedall
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,174 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Atmosphere Comments for Astro
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Bluesky comments for your Astro site, without the reader leaving the page. (On npm: [`astro-atmosphere-comments`](https://www.npmjs.com/package/astro-atmosphere-comments).)
|
|
4
|
+
|
|
5
|
+
Readers press **Respond with your Atmosphere Account**, sign in with their Bluesky handle (or any other [Atmosphere account](https://atmosphereaccount.com)), and can then:
|
|
6
|
+
|
|
7
|
+
- **comment** on your post, and **reply** to other comments;
|
|
8
|
+
- **like** and **repost** your post, or any comment under it;
|
|
9
|
+
- **quote** your post on their own profile, with a Bluesky-style preview;
|
|
10
|
+
- **@mention** people, with suggestions as they type.
|
|
11
|
+
|
|
12
|
+
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.
|
|
13
|
+
|
|
14
|
+
The component also **shows the thread**: who liked and reposted your post, and the comments, nested, with their own Reply, Like and Repost.
|
|
15
|
+
|
|
16
|
+
See it on [saltedlolly.com](https://saltedlolly.com/2005/07/13/summer-jam-party-at-miyun-reservoir/), where it was built.
|
|
17
|
+
|
|
18
|
+
## How it works
|
|
19
|
+
|
|
20
|
+
1. You announce each post on Bluesky (a post linking to it). That post's thread is the comment section.
|
|
21
|
+
2. A reader signs in with **AT Protocol OAuth, straight to their own account host** (Bluesky's, for most people). There is no third-party login service in between, and your site never sees a password.
|
|
22
|
+
3. Your site asks only for what commenting needs: to create and delete posts, likes and reposts, and to see which posts the reader has already liked or reposted. Readers can revoke it at any time in their Bluesky settings.
|
|
23
|
+
4. Your server keeps each reader's sign-in (a random cookie in their browser; their tokens on your server), and posts on their behalf when they press a button.
|
|
24
|
+
|
|
25
|
+
Images (avatars, link-card pictures) and @mention searches go through your server, so readers' browsers never contact Bluesky directly.
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- **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.
|
|
30
|
+
- **Node 20.19 or later**, with a **disk that persists** between deploys and restarts: sign-ins are stored as files. (Serverless hosts without a lasting disk aren't supported yet.)
|
|
31
|
+
- 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).
|
|
32
|
+
- Your site's **`site`** set in `astro.config`.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
npm install astro-atmosphere-comments
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 1. Add the integration
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
// astro.config.mjs
|
|
44
|
+
import { defineConfig } from "astro/config";
|
|
45
|
+
import node from "@astrojs/node";
|
|
46
|
+
import atmosphereComments from "astro-atmosphere-comments";
|
|
47
|
+
|
|
48
|
+
export default defineConfig({
|
|
49
|
+
site: "https://example.com",
|
|
50
|
+
adapter: node({ mode: "standalone" }),
|
|
51
|
+
integrations: [
|
|
52
|
+
atmosphereComments({
|
|
53
|
+
clientName: "example.com",
|
|
54
|
+
// The DIDs of the account(s) that post your announcements, and your own.
|
|
55
|
+
allowedAuthors: ["did:plc:your-did-here"],
|
|
56
|
+
logoUri: "https://example.com/logo.png",
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
To find an account's DID: `https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=you.bsky.social`.
|
|
63
|
+
|
|
64
|
+
### 2. Create your site's signing key
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
npx astro-atmosphere-comments keygen
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
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`. Set the same variable on your server, keep `.env` out of Git, and keep a backup: **a new key signs every reader out.**
|
|
71
|
+
|
|
72
|
+
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.
|
|
73
|
+
|
|
74
|
+
### 3. Put the component under your posts
|
|
75
|
+
|
|
76
|
+
```astro
|
|
77
|
+
---
|
|
78
|
+
import AtmosphereComments from "astro-atmosphere-comments/AtmosphereComments.astro";
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
<AtmosphereComments post="https://bsky.app/profile/you.bsky.social/post/3abc…" />
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`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).
|
|
85
|
+
|
|
86
|
+
### Trying it on your own computer
|
|
87
|
+
|
|
88
|
+
Run the dev server on `127.0.0.1` and open the site there, not at `localhost`:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
npx astro dev --host 127.0.0.1
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Locally the integration uses the protocol's development mode, so no key is needed and it works without a public address. Bluesky's approval screen will say a development app is asking; that's expected.
|
|
95
|
+
|
|
96
|
+
## Options
|
|
97
|
+
|
|
98
|
+
| Option | Required | What it does |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `clientName` | yes | Your site's name on the reader's sign-in screen. |
|
|
101
|
+
| `allowedAuthors` | yes | DIDs of the accounts whose posts can be commented on through your site. Comments from these accounts get the Author badge. |
|
|
102
|
+
| `logoUri` | | A square logo for the sign-in screen (absolute `https://` address). |
|
|
103
|
+
| `policyUri`, `tosUri` | | Your privacy policy and terms, shown on the sign-in screen. |
|
|
104
|
+
| `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. |
|
|
105
|
+
| `base` | | Where the integration's routes live. Default `/atmosphere`. |
|
|
106
|
+
|
|
107
|
+
## The component
|
|
108
|
+
|
|
109
|
+
| Prop | What it does |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| `post` | The announcement: bsky.app address or AT URI. Optional with Standard.site (above). |
|
|
112
|
+
| `label` | The small words on the button above "Atmosphere Account". Default "Respond with your". |
|
|
113
|
+
| `authorLabel` | The badge on your own comments. Default "Author". |
|
|
114
|
+
| `credit` | A small "Powered by Atmosphere Comments for Astro" link at the end. Default `true`; set `credit={false}` to hide it. |
|
|
115
|
+
|
|
116
|
+
**Slots:** `after-box` goes between the comment box and the comments (a note about other ways to respond, say); the default slot goes after the comments (other responses, older comments).
|
|
117
|
+
|
|
118
|
+
**Layout, top to bottom:** likes and reposts, the button (or, signed in, Like, Repost, Quote and the comment box), your `after-box` content, the comments, your default slot content.
|
|
119
|
+
|
|
120
|
+
## Styling
|
|
121
|
+
|
|
122
|
+
It has a plain default look and takes your text colour. Colours come from CSS custom properties, set on `.atmo`:
|
|
123
|
+
|
|
124
|
+
```css
|
|
125
|
+
.atmo {
|
|
126
|
+
--atmo-text: #222;
|
|
127
|
+
--atmo-muted: #666;
|
|
128
|
+
--atmo-accent: #c2185b; /* buttons, links, pressed Like */
|
|
129
|
+
--atmo-on-accent: #fff; /* text on accent buttons */
|
|
130
|
+
--atmo-border: #ddd;
|
|
131
|
+
--atmo-field-bg: #f6f6f6; /* text boxes */
|
|
132
|
+
--atmo-card-bg: #fafafa; /* comments */
|
|
133
|
+
--atmo-menu-bg: #fff; /* @mention suggestions */
|
|
134
|
+
--atmo-ring: #fff; /* the outline round faces */
|
|
135
|
+
--atmo-radius: 10px;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The likes and comments are drawn with classes you can style directly (`.atmo-reactions`, `.atmo-facepile`, `.atmo-comments`, `.atmo-comment`, `.atmo-comment--nested`, `.atmo-comment--author`, `.atmo-comment__header`, `__avatar`, `__author`, `__badge`, `__date`, `__body`, and `.atmo-comment-actions` for Reply, Like and Repost). Their defaults carry no CSS weight, so your rules always win.
|
|
140
|
+
|
|
141
|
+
## Events
|
|
142
|
+
|
|
143
|
+
The component fires (bubbling):
|
|
144
|
+
|
|
145
|
+
- `atmosphere:commented` after a comment, reply or quote is posted (`detail`: `uri`, `url`, `text`, `author`, `createdAt`, `quote`, `parent`);
|
|
146
|
+
- `atmosphere:reacted` after a like or repost of the post, or undoing one (`detail`: `kind`, `on`, `author`).
|
|
147
|
+
|
|
148
|
+
## Security and privacy
|
|
149
|
+
|
|
150
|
+
- **What your server stores:** for each signed-in reader, their DID and their OAuth tokens (which can only post, like and repost as described above), plus a random cookie value. Files are readable only by your site's user. Mention this in your privacy policy.
|
|
151
|
+
- **What it refuses:** requests that change something must come from your own pages (checked by `Origin`); only your announcements and comments in their threads can be acted on; comments, likes and searches are rate-limited per account; the image route only passes on avatars and link pictures it has just shown.
|
|
152
|
+
- **Moderation:** comments appear automatically. Hide one in the Bluesky app (it disappears here too), block the account, or add it to `hidden`.
|
|
153
|
+
- Comments are plain text, as on Bluesky: links, @mentions and #hashtags become links.
|
|
154
|
+
|
|
155
|
+
## Limitations (for now)
|
|
156
|
+
|
|
157
|
+
- Needs a Node server with a lasting disk (no serverless or edge hosts yet).
|
|
158
|
+
- Rate limits are kept in memory, so they apply per server process.
|
|
159
|
+
- The wording is English only.
|
|
160
|
+
- Quoting individual comments isn't supported.
|
|
161
|
+
|
|
162
|
+
If you only want readers to sign in with their Atmosphere account, without comments, see [AuthProto](https://www.npmjs.com/package/@fujocoded/authproto).
|
|
163
|
+
|
|
164
|
+
## Saying thanks
|
|
165
|
+
|
|
166
|
+
It's free to use (MIT), with no strings attached. If it's useful to you, I'd be grateful if you kept the small credit link, or linked to [saltedlolly.com](https://saltedlolly.com) somewhere on your site. You can also [sponsor me on GitHub](https://github.com/sponsors/saltedlolly) or [buy me a coffee on Ko-fi](https://ko-fi.com/saltedlolly).
|
|
167
|
+
|
|
168
|
+
## Credits
|
|
169
|
+
|
|
170
|
+
Made by [Olly Stedall](https://saltedlolly.com) for [saltedlolly.com](https://saltedlolly.com). The Atmosphere Account logo is from [Atmosphere Account](https://github.com/jobiwanken0bi/atmosphere-account) (MIT, © 2026 Joseph Basser).
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joseph Basser
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/assets/union.svg
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- From Atmosphere Account (https://github.com/jobiwanken0bi/atmosphere-account), MIT License, Copyright (c) 2026 Joseph Basser. See LICENSE-atmosphere-account. -->
|
|
2
|
+
<svg
|
|
3
|
+
width="32"
|
|
4
|
+
height="32"
|
|
5
|
+
viewBox="0 0 32 32"
|
|
6
|
+
fill="none"
|
|
7
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
+
>
|
|
9
|
+
<path
|
|
10
|
+
fill-rule="evenodd"
|
|
11
|
+
clip-rule="evenodd"
|
|
12
|
+
d="M16 0C18.1127 1.0372e-05 19.9555 1.15414 20.9332 2.8662C21.1045 3.16613 21.4647 3.31517 21.7979 3.22403C22.2761 3.09321 22.7795 3.02333 23.2992 3.02333C26.4347 3.02335 28.9765 5.56529 28.9765 8.70083C28.9765 9.22048 28.9066 9.72378 28.7758 10.2019C28.6846 10.5351 28.8337 10.8953 29.1336 11.0666C30.8458 12.0442 32 13.8872 32 16C32 16.0822 31.9981 16.1639 31.9946 16.2452C31.9946 16.2456 31.9944 16.246 31.9942 16.2463C31.9939 16.2465 31.9937 16.2469 31.9937 16.2473C31.8599 19.6701 29.2873 22.4 26.1329 22.4L25.9815 22.3979C24.3638 22.353 22.909 21.59 21.8719 20.3888C21.5701 20.0392 20.9949 20.0275 20.6799 20.3652C19.5117 21.6171 17.8474 22.4 16 22.4C12.4654 22.4 9.6 19.5346 9.6 16C9.6 12.4654 12.4654 9.6 16 9.6C17.4368 9.6 18.7629 10.0736 19.831 10.8731C20.0053 11.0036 20.2667 10.8843 20.2667 10.6667C20.2667 10.0776 20.7442 9.6 21.3333 9.6C21.9224 9.6 22.4 10.0776 22.4 10.6667V16C22.4158 18.5458 24.26 20.2666 26.1329 20.2667C27.9447 20.2667 29.7293 18.6564 29.8583 16.2467C29.8583 16.2466 29.8583 16.2464 29.8581 16.2463C29.858 16.2461 29.8579 16.2459 29.8579 16.2458C29.8591 16.2281 29.8597 16.2104 29.8606 16.1927C29.8634 16.1293 29.8654 16.0654 29.8658 16.001C29.8658 16.0006 29.866 16.0003 29.8663 16C29.8665 15.9997 29.8667 15.9994 29.8667 15.999C29.8663 14.5464 28.9914 13.2933 27.7308 12.7465L26.4045 12.1712C26.0876 12.0337 25.937 11.6696 26.0641 11.3484L26.5963 10.0042C26.7549 9.60324 26.8431 9.16479 26.8431 8.70083C26.8431 6.77399 25.3056 5.20644 23.3906 5.15792L23.2992 5.15667C22.8351 5.15667 22.3965 5.24487 21.9956 5.40354L20.6515 5.93568C20.3304 6.06282 19.9663 5.91222 19.8288 5.59538L19.2533 4.26917C18.7234 3.04774 17.5306 2.18836 16.1356 2.13583L16 2.13333C14.547 2.13333 13.2934 3.00824 12.7465 4.26896L12.1712 5.59529C12.0337 5.91217 11.6696 6.06282 11.3484 5.93568L10.0042 5.40354C9.62831 5.25477 9.21941 5.16798 8.7875 5.15771L8.70083 5.15667C6.74349 5.15667 5.15667 6.74349 5.15667 8.70083C5.15667 9.16475 5.24485 9.60323 5.40354 10.0042L5.93568 11.3484C6.06282 11.6696 5.91217 12.0337 5.59529 12.1712L4.26896 12.7465C3.00823 13.2934 2.13333 14.5469 2.13333 16C2.13333 17.4529 3.00832 18.7063 4.26917 19.2533L5.59538 19.8288C5.91222 19.9663 6.06282 20.3304 5.93568 20.6515L5.40354 21.9956C5.24487 22.3965 5.15667 22.835 5.15667 23.2992C5.15667 25.2565 6.74349 26.8433 8.70083 26.8433C9.1644 26.8433 9.60287 26.7551 10.0042 26.5963L11.3484 26.0641C11.6696 25.937 12.0337 26.0876 12.1712 26.4045L12.7465 27.7308C13.2934 28.9917 14.547 29.8667 16 29.8667C17.4529 29.8667 18.7063 28.9918 19.2533 27.7308L19.6555 26.8037C19.8871 26.2698 20.5083 26.0256 21.0415 26.2589C21.561 26.4862 21.8066 27.0847 21.5966 27.6115L21.2104 28.5798C20.3374 30.5922 18.3333 32 16 32C13.8872 32 12.0442 30.8458 11.0666 29.1336C10.8953 28.8337 10.5351 28.6846 10.2019 28.7758C9.72378 28.9067 9.22049 28.9767 8.70083 28.9767C5.56528 28.9767 3.02333 26.4347 3.02333 23.2992C3.02333 22.7795 3.09321 22.2761 3.22403 21.7979C3.31516 21.4647 3.16613 21.1045 2.86619 20.9332C1.15412 19.9555 0 18.1127 0 16C5.927e-07 13.8873 1.1541 12.0443 2.8662 11.0666C3.16613 10.8953 3.31517 10.5351 3.22403 10.2019C3.09323 9.72379 3.02333 9.22047 3.02333 8.70083C3.02333 5.56528 5.56528 3.02333 8.70083 3.02333C9.22047 3.02334 9.72379 3.09323 10.2019 3.22404C10.5351 3.31517 10.8953 3.16614 11.0666 2.86621C12.0443 1.15411 13.8873 0 16 0ZM16 11.7333C13.6436 11.7333 11.7333 13.6436 11.7333 16C11.7333 18.3564 13.6436 20.2667 16 20.2667C18.3564 20.2667 20.2667 18.3564 20.2667 16C20.2667 13.6436 18.3564 11.7333 16 11.7333Z"
|
|
13
|
+
fill="white"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// npx astro-atmosphere-comments keygen
|
|
3
|
+
//
|
|
4
|
+
// Creates your site's private signing key and adds it to .env (in the folder
|
|
5
|
+
// you run it from) as ATMOSPHERE_PRIVATE_JWK, without printing it. Account
|
|
6
|
+
// hosts check your site's requests against the public half, which the
|
|
7
|
+
// integration publishes at /atmosphere/jwks.json. It refuses if .env already
|
|
8
|
+
// has a key: a new key signs every reader out.
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { JoseKey } from "@atproto/oauth-client-node";
|
|
11
|
+
|
|
12
|
+
const [command] = process.argv.slice(2);
|
|
13
|
+
if (command !== "keygen") {
|
|
14
|
+
console.log("Usage: npx astro-atmosphere-comments keygen\n\nAdds a new signing key to .env as ATMOSPHERE_PRIVATE_JWK.");
|
|
15
|
+
process.exit(command ? 1 : 0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const envFile = ".env";
|
|
19
|
+
const existing = existsSync(envFile) ? readFileSync(envFile, "utf8") : "";
|
|
20
|
+
if (/^ATMOSPHERE_PRIVATE_JWK=.+/m.test(existing)) {
|
|
21
|
+
console.error("ATMOSPHERE_PRIVATE_JWK is already set in .env; leaving it alone.");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const key = await JoseKey.generate(["ES256"], "atmosphere-comments-1");
|
|
26
|
+
const line = `ATMOSPHERE_PRIVATE_JWK='${JSON.stringify(key.privateJwk)}'`;
|
|
27
|
+
const kept = existing.replace(/^ATMOSPHERE_PRIVATE_JWK=\s*$/m, "").replace(/\n*$/, existing ? "\n" : "");
|
|
28
|
+
writeFileSync(envFile, `${kept}${line}\n`, { mode: 0o600 });
|
|
29
|
+
console.log(
|
|
30
|
+
"Added ATMOSPHERE_PRIVATE_JWK to .env (not shown). Set the same value on your server, keep .env out of Git, and keep a backup somewhere safe.",
|
|
31
|
+
);
|