@geekity/plugin-wordpress 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/LICENSE +21 -0
- package/README.md +148 -2
- package/dist/bundle/index.js +160334 -0
- package/dist/bundle/plugin.json +8 -0
- package/dist/command.d.ts +17 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +194 -0
- package/dist/command.js.map +1 -0
- package/dist/federation.d.ts +30 -0
- package/dist/federation.d.ts.map +1 -0
- package/dist/federation.js +162 -0
- package/dist/federation.js.map +1 -0
- package/dist/import.d.ts +123 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +461 -0
- package/dist/import.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/records.d.ts +87 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +176 -0
- package/dist/records.js.map +1 -0
- package/dist/screen.d.ts +14 -0
- package/dist/screen.d.ts.map +1 -0
- package/dist/screen.js +78 -0
- package/dist/screen.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +51 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andrew Shell
|
|
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,149 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @geekity/plugin-wordpress
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A [Geekity CMS](../cms/README.md) plugin for a site that moved from the
|
|
4
|
+
WordPress ActivityPub plugin. It answers the old plugin's inbox and collection
|
|
5
|
+
paths until every follower's server has refetched the actor, records when each
|
|
6
|
+
path was last asked for, and adds `geekity import wordpress-actor`, which
|
|
7
|
+
brings each person's key pair, actor id and followers across.
|
|
8
|
+
|
|
9
|
+
A site born on the CMS never needs it. Stored actor ids, post object ids,
|
|
10
|
+
WebFinger aliases and the feed and archive layout are the site's own and are in
|
|
11
|
+
`@geekity/cms` (decision-14).
|
|
12
|
+
|
|
13
|
+
## Installing it
|
|
14
|
+
|
|
15
|
+
Add the package to the site and to `plugins` in its config:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
pnpm add @geekity/plugin-wordpress
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { defineConfig } from '@geekity/cms';
|
|
23
|
+
import wordpress from '@geekity/plugin-wordpress';
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
plugins: [wordpress],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
On Docker, add the package to the plugins folder instead, then press Reload
|
|
31
|
+
under `/admin/plugins`:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
docker compose exec geekity geekity plugin add @geekity/plugin-wordpress
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`geekity import wordpress-actor` works as soon as the plugin is installed. The
|
|
38
|
+
old paths are served only while the plugin is enabled under `/admin/plugins`,
|
|
39
|
+
and disabling it takes them away on the next request, with nothing restarted.
|
|
40
|
+
|
|
41
|
+
The plugin keeps two files in `data/plugins/@geekity/plugin-wordpress/`:
|
|
42
|
+
|
|
43
|
+
| File | What it holds |
|
|
44
|
+
| --------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| `actors.json` | Each username and the number WordPress gave that person's actor, which the old paths are built from. Written by the import. |
|
|
46
|
+
| `requests.json` | When each old path was last asked for, per user, and when the shared inbox was. Losing it resets what the screen says. |
|
|
47
|
+
|
|
48
|
+
## The old paths
|
|
49
|
+
|
|
50
|
+
A follower's server still holds the WordPress plugin's endpoints, such as
|
|
51
|
+
`/wp-json/activitypub/1.0/actors/2/inbox`, the shared
|
|
52
|
+
`/wp-json/activitypub/1.0/inbox`, and the collections beside them. Those are
|
|
53
|
+
cache rather than identity: a follower's server replaces them the next time it
|
|
54
|
+
refetches the actor. So the site carries them for a while, and is meant to
|
|
55
|
+
stop.
|
|
56
|
+
|
|
57
|
+
While the plugin is enabled, those paths are real inbox routes,
|
|
58
|
+
signature-verified exactly as the site's own are, so an unsigned or badly
|
|
59
|
+
signed delivery is refused, plus GET routes for the actor, its outbox, its
|
|
60
|
+
followers and its following. What a peer reads back is always the canonical
|
|
61
|
+
document: the same `id`, the same key, and the _canonical_ inbox and
|
|
62
|
+
collections, so a follower refetching the actor at the old URL is the follower
|
|
63
|
+
that learns the new endpoints. A user with no number in `actors.json` is not
|
|
64
|
+
reachable through any of it.
|
|
65
|
+
|
|
66
|
+
Every one of those paths records the instant it was last asked for, and the
|
|
67
|
+
plugin's screen under Plugins, `/admin/plugins/@geekity/plugin-wordpress`,
|
|
68
|
+
lists each path with that instant, or _Never_. Once every follower's server has
|
|
69
|
+
refetched the actor, nothing asks any more, and the plugin can be disabled.
|
|
70
|
+
|
|
71
|
+
## Bringing a person across
|
|
72
|
+
|
|
73
|
+
`geekity import wordpress-actor` brings one person across. It writes the three
|
|
74
|
+
things the site cannot mint for itself, the RSA key pair the followers have
|
|
75
|
+
cached, the actor id they key the account by, and the followers, and it is a
|
|
76
|
+
command rather than a screen because a stored actor id is identity for the life
|
|
77
|
+
of the account.
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
geekity import wordpress-actor ada \
|
|
81
|
+
--actor-id 'https://example.com/?author=2' \
|
|
82
|
+
--wordpress-id 2 \
|
|
83
|
+
--keypair ada.keypair.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
It writes `data/keys/ada.rsassa-pkcs1-v1_5.jwk` (and mints the Ed25519 pair
|
|
87
|
+
beside it, which WordPress never had), puts `actorId` on the user in
|
|
88
|
+
`data/users.json` and the number in the plugin's `actors.json`, and fetches the
|
|
89
|
+
WordPress plugin's public followers collection into
|
|
90
|
+
`content/_data/federation/ada/followers.json`, dereferencing each follower for
|
|
91
|
+
its inbox, shared inbox, handle, name, avatar and profile URL.
|
|
92
|
+
|
|
93
|
+
| Option | What it is |
|
|
94
|
+
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
95
|
+
| `--actor-id <url>` | The id WordPress published, query string and all. The one thing the import cannot work out for itself. |
|
|
96
|
+
| `--wordpress-id <n>` | The WordPress user id, which is the number in the plugin's paths. |
|
|
97
|
+
| `--keypair <file>` | The JSON the plugin's option holds: `{"private_key": …, "public_key": …}`. |
|
|
98
|
+
| `--private-key <file>`, `--public-key <file>` | The two PEMs instead, for a site still on the legacy user meta. The public key is only checked against the private half; it is derived, never stored. |
|
|
99
|
+
| `--followers <url\|file\|none>` | Where the followers come from. Left off, the plugin's own collection on the actor id's origin. |
|
|
100
|
+
| `--force` | Import over a key pair the user already has. |
|
|
101
|
+
|
|
102
|
+
**Exporting the key pair with wp-cli.** The WordPress plugin keeps a user's
|
|
103
|
+
pair in an option named after their login:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
# On the WordPress server. The login, not the user id, is what names the option.
|
|
107
|
+
wp option get activitypub_keypair_for_ada --format=json > ada.keypair.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A site old enough to still be on the plugin's legacy storage has the pair in
|
|
111
|
+
user meta instead, one PEM per key:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
wp user meta get 2 magic_sig_private_key > ada.private.pem
|
|
115
|
+
wp user meta get 2 magic_sig_public_key > ada.public.pem
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Either export is accepted, and either PEM encoding, `-----BEGIN PRIVATE
|
|
119
|
+
KEY-----` (PKCS#8) or `-----BEGIN RSA PRIVATE KEY-----` (PKCS#1). Treat the
|
|
120
|
+
files the way you would treat a password: the private key is the account.
|
|
121
|
+
|
|
122
|
+
The followers can be saved before the old site goes away, and the saved file
|
|
123
|
+
passed to `--followers`:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
curl -H 'Accept: application/activity+json' \
|
|
127
|
+
'https://example.com/wp-json/activitypub/1.0/actors/2/followers?page=1' > followers.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Running it twice changes nothing**, and says so, which is what makes it safe
|
|
131
|
+
to run again after an instance that was down comes back: a follower already in
|
|
132
|
+
the file keeps its place and its follow time. A follower whose server will not
|
|
133
|
+
answer is listed and skipped rather than failing the import. A user who already
|
|
134
|
+
has a _different_ key pair is refused: importing over one would change that
|
|
135
|
+
person's identity, and every follower has cached the public half of the key
|
|
136
|
+
that is there. `--force` is the way past that, and is only right when you are
|
|
137
|
+
certain the pair being imported is the one the followers hold. An actor id or a
|
|
138
|
+
WordPress number another user already carries is refused too, before anything
|
|
139
|
+
is written.
|
|
140
|
+
|
|
141
|
+
The cutover, end to end, is in the `@geekity/cms` README under _Moving a site
|
|
142
|
+
from the WordPress ActivityPub plugin_.
|
|
143
|
+
|
|
144
|
+
## The bundle
|
|
145
|
+
|
|
146
|
+
The package's build also writes `dist/bundle/index.js`, one module with its
|
|
147
|
+
dependencies inlined and the plugin as its default export. It is what a
|
|
148
|
+
plugins folder holds on a site that runs the Docker image, which has no
|
|
149
|
+
`node_modules` of its own (decision-33).
|