fedipod 1.5.0 → 1.6.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/README.md +5 -5
- package/architecture.md +4 -4
- package/cli.md +7 -0
- package/gateway.md +1 -1
- package/groups.md +1 -1
- package/gui.md +1 -1
- package/lib/core/publisher/index.mjs +1 -1
- package/lib/device/admin/routes/lifecycle.mjs +1 -1
- package/lib/device/admin/routes/setup.mjs +20 -1
- package/lib/device/cli/commands/setup.mjs +44 -20
- package/lib/device/setup.mjs +99 -25
- package/lib/pod/root.mjs +1 -1
- package/package.json +1 -1
- package/web/admin/setup/index.html +25 -2
- package/web/admin/setup/setup.js +30 -1
- package/web/app/README.md +2 -2
- package/web/app/admin-facade.mjs +1 -1
- package/web/app/agent.mjs +2 -2
- package/web/app/boot.mjs +2 -2
- package/web/app/dist/boot.js +1 -1
- package/web/app/dist/boot.js.map +2 -2
- package/web/app/dist/sw.js +3 -3
- package/web/app/dist/sw.js.map +2 -2
- package/web/app/index.html +1 -1
- package/web/app/signup.mjs +2 -2
- package/web/app/site/admin/setup/index.html +25 -2
- package/web/app/site/admin/setup/setup.js +30 -1
- package/web/app/site/boot.js +1 -1
- package/web/app/site/index.html +1 -1
- package/web/app/site/sw.js +3 -3
- package/installed-agent.md +0 -97
package/web/app/index.html
CHANGED
|
@@ -170,7 +170,7 @@ a { color: var(--accent); }
|
|
|
170
170
|
<input type="url" id="pod" name="pod" autocomplete="url" aria-describedby="pod-hint"
|
|
171
171
|
placeholder="https://alice.solidcommunity.net/ or https://server.example/alice/">
|
|
172
172
|
<p class="hint" id="pod-hint">The address of your pod: its own host, or a path on a
|
|
173
|
-
|
|
173
|
+
suffix-based host.</p>
|
|
174
174
|
</div>
|
|
175
175
|
|
|
176
176
|
<label for="email">Email (used as pod id)</label>
|
package/web/app/signup.mjs
CHANGED
|
@@ -53,7 +53,7 @@ const progressKey = (a) => [a.issuer, a.mode, a.handle, a.mode === 'new' ? (a.po
|
|
|
53
53
|
* `shape` is where the address lives. On the pod, `@handle@yourpod`, with the
|
|
54
54
|
* gateway as a mail door only — the default. At the gateway, `@handle@front`,
|
|
55
55
|
* a fronted identity whose documents still live on the pod. A pod on a path of
|
|
56
|
-
* a
|
|
56
|
+
* a suffix-based host cannot answer WebFinger, so it is fronted whatever was asked.
|
|
57
57
|
*
|
|
58
58
|
* returns: { credential, config, actorUrl, address, keysPublic }
|
|
59
59
|
*/
|
|
@@ -116,7 +116,7 @@ export async function signUp(answers, { onStep = () => {}, frontOrigin = null }
|
|
|
116
116
|
const pathPod = new URL(pod).pathname !== '/';
|
|
117
117
|
const fronted = pathPod || wantsFront;
|
|
118
118
|
if (fronted && !frontOrigin) {
|
|
119
|
-
throw new Error(`${pod} is a
|
|
119
|
+
throw new Error(`${pod} is a suffix-based host, so its address must live at a gateway, and this page has none.`);
|
|
120
120
|
}
|
|
121
121
|
if (pathPod && !wantsFront) await assertFrontNameFree(frontOrigin, handle);
|
|
122
122
|
|
|
@@ -132,9 +132,20 @@ button:disabled { opacity: .5; cursor: default; }
|
|
|
132
132
|
<label for="issuer-new">Solid pod provider</label>
|
|
133
133
|
<select id="issuer-new" name="issuerNew" aria-describedby="issuer-new-hint">
|
|
134
134
|
<option value="https://solidcommunity.net">solidcommunity.net</option>
|
|
135
|
+
<option value="https://privatedatapod.com">privatedatapod.com</option>
|
|
136
|
+
<option value="https://solid.redpencil.io">redpencil.io</option>
|
|
137
|
+
<option value="https://pods.solidcommunity.au">solidcommunity.au</option>
|
|
138
|
+
<option value="https://solidweb.me">solidweb.me</option>
|
|
139
|
+
<option value="https://teamid.live">teamid.live</option>
|
|
140
|
+
<option value="">Other…</option>
|
|
135
141
|
</select>
|
|
136
|
-
<
|
|
137
|
-
|
|
142
|
+
<div id="row-issuer-other" hidden>
|
|
143
|
+
<label for="issuerOther">Provider address</label>
|
|
144
|
+
<input type="url" id="issuerOther" name="issuerOther" autocomplete="url" placeholder="https://pods.example.org">
|
|
145
|
+
</div>
|
|
146
|
+
<p class="hint" id="issuer-new-hint">The Community Solid Server providers from
|
|
147
|
+
solidproject.org. A provider that puts pods on paths gives your address at a
|
|
148
|
+
gateway instead.</p>
|
|
138
149
|
</div>
|
|
139
150
|
|
|
140
151
|
<div id="row-issuer-existing" hidden>
|
|
@@ -172,6 +183,18 @@ button:disabled { opacity: .5; cursor: default; }
|
|
|
172
183
|
Wrong account or pod?
|
|
173
184
|
<button type="button" id="form-reenter" title=" Discard the credential and enter the account and pod again">Re-enter credentials</button></p>
|
|
174
185
|
|
|
186
|
+
<fieldset id="fs-shape" hidden>
|
|
187
|
+
<legend>Where your address lives</legend>
|
|
188
|
+
<label class="choice"><input type="radio" name="shape" value="pod" checked> On your pod</label>
|
|
189
|
+
<label class="choice"><input type="radio" name="shape" value="front"> At a gateway</label>
|
|
190
|
+
<div id="row-gateway" hidden>
|
|
191
|
+
<label for="gatewayOrigin">Gateway</label>
|
|
192
|
+
<input type="url" id="gatewayOrigin" name="gatewayOrigin" value="https://fedipod.net" autocomplete="url">
|
|
193
|
+
<p class="hint">The gateway answers your address and forwards your mail to your pod.</p>
|
|
194
|
+
</div>
|
|
195
|
+
<p class="hint" id="shape-note" hidden></p>
|
|
196
|
+
</fieldset>
|
|
197
|
+
|
|
175
198
|
<h2>You will be</h2>
|
|
176
199
|
<p class="address" id="preview">…</p>
|
|
177
200
|
<div id="preview-notes"></div>
|
|
@@ -93,12 +93,18 @@ function answers() {
|
|
|
93
93
|
const f = $('form').elements;
|
|
94
94
|
const kind = f.kind.value;
|
|
95
95
|
const mode = state.resumable ? 'existing' : f.mode.value;
|
|
96
|
+
const issuer = mode === 'new'
|
|
97
|
+
? (f.issuerNew.value || (f.issuerOther ? f.issuerOther.value : '')).trim()
|
|
98
|
+
: f.issuer.value.trim();
|
|
96
99
|
const a = {
|
|
97
100
|
kind,
|
|
98
101
|
mode,
|
|
99
102
|
handle: f.handle.value.trim(),
|
|
100
|
-
issuer
|
|
103
|
+
issuer,
|
|
101
104
|
email: f.email.value.trim(),
|
|
105
|
+
// Where the address lives; a group cannot front (yet), so it stays 'pod'.
|
|
106
|
+
shape: (kind === 'group') ? 'pod' : (f.shape ? f.shape.value : 'pod'),
|
|
107
|
+
gatewayOrigin: (f.gatewayOrigin ? f.gatewayOrigin.value.trim() : '') || 'https://fedipod.net',
|
|
102
108
|
};
|
|
103
109
|
if (mode === 'new') a.podName = f.podName.value.trim() || a.handle;
|
|
104
110
|
else a.pod = f.pod.value.trim();
|
|
@@ -128,6 +134,9 @@ function onEdit() {
|
|
|
128
134
|
$('row-pod').hidden = mode === 'new';
|
|
129
135
|
$('row-issuer-new').hidden = mode !== 'new';
|
|
130
136
|
$('row-issuer-existing').hidden = mode === 'new';
|
|
137
|
+
const f = $('form').elements;
|
|
138
|
+
if ($('row-issuer-other')) $('row-issuer-other').hidden = !(mode === 'new' && f.issuerNew.value === '');
|
|
139
|
+
if ($('row-gateway')) $('row-gateway').hidden = !(f.shape && f.shape.value === 'front');
|
|
131
140
|
clearTimeout(editTimer);
|
|
132
141
|
editTimer = setTimeout(preview, 150);
|
|
133
142
|
}
|
|
@@ -140,6 +149,26 @@ async function preview() {
|
|
|
140
149
|
const { json } = await postJson('/setup/check', a);
|
|
141
150
|
if (!json) return;
|
|
142
151
|
$('preview').textContent = json.address || '…';
|
|
152
|
+
// The address-shape choice: hidden for a group (a group cannot front yet),
|
|
153
|
+
// locked to the gateway for a pod on a suffix-based host, an open choice
|
|
154
|
+
// for a pod at its own host.
|
|
155
|
+
const f = $('form').elements;
|
|
156
|
+
const shapeFs = $('fs-shape');
|
|
157
|
+
if (shapeFs) {
|
|
158
|
+
const isGroup = a.kind === 'group';
|
|
159
|
+
shapeFs.hidden = isGroup || (a.mode === 'existing' && !a.pod);
|
|
160
|
+
const forced = !!json.forced;
|
|
161
|
+
for (const r of f.shape) r.disabled = forced;
|
|
162
|
+
if (forced) { for (const r of f.shape) r.checked = r.value === 'front'; }
|
|
163
|
+
if ($('row-gateway')) $('row-gateway').hidden = !(f.shape.value === 'front');
|
|
164
|
+
const note = $('shape-note');
|
|
165
|
+
if (note) {
|
|
166
|
+
note.hidden = !forced;
|
|
167
|
+
note.textContent = forced
|
|
168
|
+
? 'Your pod is on a suffix-based host, so its address lives at the gateway. Your posts, key and data stay on your pod.'
|
|
169
|
+
: '';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
143
172
|
const notes = $('preview-notes');
|
|
144
173
|
for (const w of json.warnings || []) {
|
|
145
174
|
const p = document.createElement('p');
|
package/web/app/site/boot.js
CHANGED
|
@@ -33321,7 +33321,7 @@ async function signUp(answers, { onStep = () => {
|
|
|
33321
33321
|
const pathPod = new URL(pod).pathname !== "/";
|
|
33322
33322
|
const fronted = pathPod || wantsFront;
|
|
33323
33323
|
if (fronted && !frontOrigin) {
|
|
33324
|
-
throw new Error(`${pod} is a
|
|
33324
|
+
throw new Error(`${pod} is a suffix-based host, so its address must live at a gateway, and this page has none.`);
|
|
33325
33325
|
}
|
|
33326
33326
|
if (pathPod && !wantsFront) await assertFrontNameFree(frontOrigin, handle);
|
|
33327
33327
|
const actorUrl = actorUrlFor(pod);
|
package/web/app/site/index.html
CHANGED
|
@@ -170,7 +170,7 @@ a { color: var(--accent); }
|
|
|
170
170
|
<input type="url" id="pod" name="pod" autocomplete="url" aria-describedby="pod-hint"
|
|
171
171
|
placeholder="https://alice.solidcommunity.net/ or https://server.example/alice/">
|
|
172
172
|
<p class="hint" id="pod-hint">The address of your pod: its own host, or a path on a
|
|
173
|
-
|
|
173
|
+
suffix-based host.</p>
|
|
174
174
|
</div>
|
|
175
175
|
|
|
176
176
|
<label for="email">Email (used as pod id)</label>
|
package/web/app/site/sw.js
CHANGED
|
@@ -56507,7 +56507,7 @@ var Publisher = class {
|
|
|
56507
56507
|
}
|
|
56508
56508
|
const pubName = publicHandle(this.config);
|
|
56509
56509
|
const pubHost = this.config.gateway?.frontActor ? new URL(this.config.gateway.frontActor).host : host;
|
|
56510
|
-
this.log(this.config.gateway?.frontActor || webfingerHost(urls.base) ? `profile published: @${pubName}@${pubHost} \u2192 ${urls.actor}` : `profile published \u2192 ${urls.actor} \u2014 NOT discoverable as @${pubName}@${pubHost}: this pod is a
|
|
56510
|
+
this.log(this.config.gateway?.frontActor || webfingerHost(urls.base) ? `profile published: @${pubName}@${pubHost} \u2192 ${urls.actor}` : `profile published \u2192 ${urls.actor} \u2014 NOT discoverable as @${pubName}@${pubHost}: this pod is a suffix-based host, and WebFinger is only answered at a host root`);
|
|
56511
56511
|
return { unreachable, updated };
|
|
56512
56512
|
}
|
|
56513
56513
|
// Fires when the document differs from the one last published — including
|
|
@@ -68273,7 +68273,7 @@ var AdminFacade = class {
|
|
|
68273
68273
|
const aliases = [...cfg.aliases || []];
|
|
68274
68274
|
if (body.add) {
|
|
68275
68275
|
if (!webfingerHost(urls.base) && !cfg.gateway?.frontActor) {
|
|
68276
|
-
return json2(400, { error: "this pod is a
|
|
68276
|
+
return json2(400, { error: "this pod is a suffix-based host, so other servers could never resolve it as a Move target" });
|
|
68277
68277
|
}
|
|
68278
68278
|
const id = await this.resolveActor(body.add);
|
|
68279
68279
|
if (!id) return json2(400, { error: `could not fetch the old account (${body.add}) \u2014 enter its URL or @user@host, and it must answer` });
|
|
@@ -69785,7 +69785,7 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
69785
69785
|
publicKeyPem: keys.rsaPublicPem,
|
|
69786
69786
|
assertionKey: null,
|
|
69787
69787
|
log: this.log,
|
|
69788
|
-
// Who a post names, resolved — the same lookup the
|
|
69788
|
+
// Who a post names, resolved — the same lookup the DeviceAgent
|
|
69789
69789
|
// gives its publisher. Without it no mention from the browser ever
|
|
69790
69790
|
// resolved: a direct message went to nobody, a mention notified no one.
|
|
69791
69791
|
resolveMention: (h) => resolveHandle(this, h)
|
package/installed-agent.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# The installed agent
|
|
2
|
-
|
|
3
|
-
FediPod can also run as a program on your own machine, in front of the same
|
|
4
|
-
kind of pod. It does everything the browser version at fedipod.net does, plus
|
|
5
|
-
what a browser tab cannot: it keeps running while no tab is open, so scheduled
|
|
6
|
-
posts go out and push notifications reach you; it serves the Mastodon streaming
|
|
7
|
-
API, so clients update live; any Mastodon client, phone app or desktop, can
|
|
8
|
-
connect to it; and it can host a [group](groups.md).
|
|
9
|
-
|
|
10
|
-
## Requirements
|
|
11
|
-
|
|
12
|
-
- Node 20 or newer.
|
|
13
|
-
- A Solid pod with a host name of its own, such as
|
|
14
|
-
`https://alice.solidcommunity.net/`. A pod on a path of a shared host cannot
|
|
15
|
-
be a Fediverse address.
|
|
16
|
-
- Followers-only and direct posts need a pod that enforces WAC access control;
|
|
17
|
-
on one that does not, the composer refuses those two and says why.
|
|
18
|
-
- While the agent is off, your mail waits on your pod's host. Run it as a
|
|
19
|
-
service, or attach to a gateway, so it does not pile up there.
|
|
20
|
-
|
|
21
|
-
## Installing
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
npm install -g fedipod
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Running
|
|
28
|
-
|
|
29
|
-
Run `fedipod start`. Add a port to change the local agent's port, for example
|
|
30
|
-
`fedipod start --port 8081`; the default is 8030. Then point any browser at
|
|
31
|
-
`https://localhost:8030`, or the port you chose, and the setup pages take it
|
|
32
|
-
from there.
|
|
33
|
-
|
|
34
|
-
## Running as a service
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
fedipod install-service
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
It registers every identity on this machine, one service each, so all of your
|
|
41
|
-
actors start at boot. An identity running in a terminal is stopped and taken
|
|
42
|
-
over by its service. `fedipod uninstall-service` reverses it.
|
|
43
|
-
|
|
44
|
-
## Managing
|
|
45
|
-
|
|
46
|
-
Posts, logs, parking, moving, transferring and the rest are on the
|
|
47
|
-
[admin interface](gui.md); starting, stopping and what a page cannot do are in
|
|
48
|
-
[CLI admin](cli.md). The admin tools also create other actors, groups or
|
|
49
|
-
persons. You may have as many as you want on one machine, each with a pod of
|
|
50
|
-
its own.
|
|
51
|
-
|
|
52
|
-
Every agent checks once a day whether a newer FediPod is published. When one
|
|
53
|
-
exists, the record page offers **Update**, and `fedipod update` does the same
|
|
54
|
-
from the terminal. `AP_UPDATE_CHECK=0` turns the check off.
|
|
55
|
-
|
|
56
|
-
## A gateway account
|
|
57
|
-
|
|
58
|
-
Most of what a Fediverse inbox receives is broadcast noise. A
|
|
59
|
-
[gateway](gateway.md) is a shared, always-on door that verifies each delivery,
|
|
60
|
-
drops the junk, and passes the rest to your pod, while your key and data stay
|
|
61
|
-
on your pod. There is a free one at [fedipod.net](https://fedipod.net/).
|
|
62
|
-
Attaching or detaching is a few wizard-guided clicks from your agent, and it
|
|
63
|
-
takes the mail load off your pod's host.
|
|
64
|
-
|
|
65
|
-
## Clients
|
|
66
|
-
|
|
67
|
-
The bundled client is [Phanpy](https://github.com/cheeaun/phanpy) (MIT, by
|
|
68
|
-
Chee Aun), served by the agent itself, and logging in is one click. If you
|
|
69
|
-
ever enter the instance by hand, use the address on the record's **local
|
|
70
|
-
host** row.
|
|
71
|
-
|
|
72
|
-
- **Other web clients**: drop any static Mastodon client dist into
|
|
73
|
-
`ui/<name>/` and it is served at `/<name>/`; see `ui/README.md`.
|
|
74
|
-
- **Desktop and phone clients** (Tuba, Whalebird, and the like): add
|
|
75
|
-
`https://localhost:8030`, or your agent's port, as a custom instance.
|
|
76
|
-
- **Streaming**: the agent serves the Mastodon streaming API at
|
|
77
|
-
`/api/v1/streaming`, so clients update live instead of polling.
|
|
78
|
-
- **Web push**: notifications reach you while the client is closed.
|
|
79
|
-
- **Scheduled posts** go out at the time you picked.
|
|
80
|
-
|
|
81
|
-
Polls, content warnings, editing, all four visibility levels, direct
|
|
82
|
-
messages, bookmarks, favourites, lists, keyword filters, pinned posts,
|
|
83
|
-
blocking and muting, and custom emojis work as in the browser version.
|
|
84
|
-
|
|
85
|
-
## Bluesky, and your other Fediverse accounts
|
|
86
|
-
|
|
87
|
-
A Bluesky connection lets the agent drive an existing Bluesky, or other
|
|
88
|
-
ATProto, account alongside your Fediverse identity: public posts are
|
|
89
|
-
cross-posted as a mirror, with a toggle to turn it off; Bluesky replies and
|
|
90
|
-
activity flow into your timeline; you can like, boost and reply to Bluesky
|
|
91
|
-
posts. Direct messages to Bluesky are not supported.
|
|
92
|
-
|
|
93
|
-
An account on Mastodon or any server speaking the Mastodon API can be
|
|
94
|
-
connected from the **Other identities** row of the admin page. Its home
|
|
95
|
-
timeline and notifications join your feed, a post both accounts see appears
|
|
96
|
-
once, and favouriting, boosting and replying act as the account the post came
|
|
97
|
-
through. The token it hands back stays on this machine.
|