fedipod 1.40.0 → 1.42.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 -0
- package/architecture.md +1 -3
- package/architecture.svg +93 -85
- package/gateway.md +7 -2
- package/lib/client/c2s.mjs +16 -5
- package/lib/client/masto/oauth.mjs +1 -1
- package/lib/connections/vault.mjs +1 -1
- package/lib/core/agent.mjs +720 -0
- package/lib/core/gateway-move.mjs +58 -0
- package/lib/core/keys.mjs +1 -1
- package/lib/core/lease.mjs +4 -3
- package/lib/core/publisher/index.mjs +4 -6
- package/lib/core/publisher/notes.mjs +73 -4
- package/lib/core/remote.mjs +54 -0
- package/lib/core/shapes/shapes-text.mjs +11 -3
- package/lib/core/wire.mjs +4 -1
- package/lib/device/admin/index.mjs +4 -11
- package/lib/device/admin/routes/setup.mjs +60 -5
- package/lib/device/admin/server.mjs +18 -5
- package/lib/device/cli/commands/account.mjs +1 -1
- package/lib/device/cli/commands/run.mjs +2 -2
- package/lib/device/cli/commands/service.mjs +1 -1
- package/lib/device/cli/commands/setup.mjs +1 -1
- package/lib/device/cli/commands/state.mjs +1 -1
- package/lib/device/cli/context.mjs +1 -1
- package/lib/{gateway → device}/directory.mjs +1 -1
- package/lib/device/gateway-move.mjs +3 -58
- package/lib/device/home.mjs +3 -50
- package/lib/{client → device}/localapi.mjs +2 -2
- package/lib/device/remote.mjs +3 -54
- package/lib/gateway/copy.mjs +7 -1
- package/lib/gateway/front-core.mjs +6 -16
- package/lib/gateway/front-pages.mjs +31 -0
- package/lib/gateway/keeper-session.mjs +10 -1
- package/lib/gateway/masto-gateway.mjs +61 -12
- package/lib/gateway/outbox-door.mjs +31 -0
- package/lib/gateway/state-api.mjs +39 -7
- package/lib/server/embed.mjs +4 -4
- package/lib/shared/files.mjs +49 -0
- package/lib/shared/ua.mjs +3 -0
- package/lib/surface/index.mjs +7 -0
- package/lib/{device/admin → surface}/origins.mjs +1 -1
- package/lib/{device/admin → surface}/routes/gateway.mjs +7 -11
- package/lib/{device/admin → surface}/routes/lifecycle.mjs +3 -3
- package/lib/{device/admin → surface}/routes/owner.mjs +4 -60
- package/lib/{device/admin → surface}/routes/social.mjs +1 -1
- package/lib/{device/admin → surface}/static.mjs +6 -1
- package/lib/{device/admin → surface}/surface.mjs +19 -16
- package/package.json +23 -5
- package/run-agent.mjs +18 -714
- package/scripts/build-app.mjs +4 -0
- package/scripts/check-netlify-bundles.mjs +84 -0
- package/scripts/check-pod-calls.mjs +42 -0
- package/scripts/vendor-sanitize.mjs +27 -0
- package/vendor/idp-grant.cjs +11 -5
- package/vendor/sanitize-html.cjs +11456 -0
- package/web/app/agent.mjs +4 -2
- package/web/app/copy-mode.mjs +27 -3
- package/web/app/dist/boot.js.map +1 -1
- package/web/app/dist/sw.js +110 -24
- package/web/app/dist/sw.js.map +4 -4
- package/web/app-signin/app-signin.mjs +2 -2
- package/web/app-signin/index.html +13 -5
- package/browser.svg +0 -72
- /package/lib/{device/admin → surface}/routes/connections.mjs +0 -0
package/web/app/agent.mjs
CHANGED
|
@@ -34,7 +34,7 @@ import { AcctFeed } from '../../lib/connections/acctfeed.mjs';
|
|
|
34
34
|
import { followActor, unfollowActor, resolveHandle } from '../../lib/core/social.mjs';
|
|
35
35
|
import { podBaseOfWebId } from '../../lib/pod/urls.mjs';
|
|
36
36
|
import { ImportWorker } from '../../lib/connections/import.mjs';
|
|
37
|
-
import { openCopy, copyStorage, copyLeaseOf, moveIntoCopy, leaveCopy, renewCopyToken, standDown, ensureCopyLease, handOverCopy } from './copy-mode.mjs';
|
|
37
|
+
import { openCopy, copyStorage, copyLeaseOf, moveIntoCopy, leaveCopy, renewCopyToken, standDown, ensureCopyLease, handOverCopy, forgetFailedOpen } from './copy-mode.mjs';
|
|
38
38
|
|
|
39
39
|
// The authorities this identity answers on: exactly one, this origin. The Node
|
|
40
40
|
// agent gets this from lib/guard.mjs, which is not in the browser bundle and
|
|
@@ -191,6 +191,8 @@ export class BrowserAgent {
|
|
|
191
191
|
if (!on) return { status: 200, ok: true, kept: false };
|
|
192
192
|
const said = await this.tellGateway('keeper', { handle: this.doorKey, on: true });
|
|
193
193
|
if (said?.status === 200) {
|
|
194
|
+
// A copy that could not be had while the account was not kept may be now.
|
|
195
|
+
await forgetFailedOpen(this, this.frontOrigin);
|
|
194
196
|
this._keeper.kept = true;
|
|
195
197
|
if (this.masto) this.masto.scheduling = true;
|
|
196
198
|
this.log('the gateway keeps this account running while the app is closed');
|
|
@@ -420,7 +422,7 @@ export class BrowserAgent {
|
|
|
420
422
|
// is read, since it decides where the state is read from.
|
|
421
423
|
this.holderId = await this.deviceId();
|
|
422
424
|
this.frontOrigin = frontOrigin || null;
|
|
423
|
-
this.copy = await openCopy(this, this.frontOrigin, { kept: isWarm(warmFrom) ? warmFrom.copy : null });
|
|
425
|
+
this.copy = await openCopy(this, this.frontOrigin, { kept: isWarm(warmFrom) ? warmFrom.copy : null, askAnyway: !restart });
|
|
424
426
|
const warmRoot = isWarm(warmFrom) && !!warmFrom.copy === !!this.copy ? warmFrom.root : null;
|
|
425
427
|
const copyRoot = this.copy?.podHome?.startsWith(remotePod) ? this.copy.podHome.slice(remotePod.length) : null;
|
|
426
428
|
this._sweptAt = { ...(warmFrom?.sweptAt || {}) };
|
package/web/app/copy-mode.mjs
CHANGED
|
@@ -8,19 +8,38 @@
|
|
|
8
8
|
// gateway writes the copy to the pod every fifteen minutes.
|
|
9
9
|
import { HttpStorage, StateApiStorage, podOnly } from '../../lib/core/storage.mjs';
|
|
10
10
|
import { Lease } from '../../lib/core/lease.mjs';
|
|
11
|
+
import { kvGet, kvPut, kvDel } from './idb-kv.mjs';
|
|
11
12
|
|
|
12
13
|
// A token this much short of its end is renewed before it is used again.
|
|
13
14
|
const RENEW_BEFORE_MS = 2 * 3600_000;
|
|
14
15
|
|
|
16
|
+
// After the gateway could not find or make the copy, this browser does not
|
|
17
|
+
// ask again for this long: its worker is restarted whenever a client checks
|
|
18
|
+
// for posts, about once a minute, and every ask cost the gateway a try at the
|
|
19
|
+
// pod. The account works from its pod meanwhile, as after any failed ask. A
|
|
20
|
+
// sign-in, as against a restart, asks anyway, and turning keeping on forgets
|
|
21
|
+
// the failure (agent.mjs setKeeper). A network failure or a refused sign-in is
|
|
22
|
+
// not remembered: those are this browser's to put right. Nor is "held by
|
|
23
|
+
// another device" after this browser lets go of the pod (moveIntoCopy): what
|
|
24
|
+
// the gateway found held may have been this browser's own lease.
|
|
25
|
+
const ASK_AGAIN_MS = 15 * 60_000;
|
|
26
|
+
const REMEMBERED = [404, 409, 501, 502, 503];
|
|
27
|
+
const failedKey = (agent, frontOrigin) => `copy-open-failed:${frontOrigin}:${agent.webId}`;
|
|
28
|
+
export const forgetFailedOpen = (agent, frontOrigin) => kvDel(failedKey(agent, frontOrigin)).catch(() => {});
|
|
29
|
+
|
|
15
30
|
/**
|
|
16
31
|
* Ask the gateway for this account's copy, making it if there is none yet.
|
|
17
32
|
* `handle` names the account when the agent knows it. Returns the copy
|
|
18
33
|
* ({ handle, base, token, expiresAt }) or null, in which case the account
|
|
19
34
|
* works from its pod.
|
|
20
35
|
*/
|
|
21
|
-
export async function openCopy(agent, frontOrigin, { handle = null, kept = null } = {}) {
|
|
36
|
+
export async function openCopy(agent, frontOrigin, { handle = null, kept = null, askAnyway = false, letGo = false } = {}) {
|
|
22
37
|
if (kept && kept.expiresAt - Date.now() > RENEW_BEFORE_MS) return kept;
|
|
23
38
|
if (!agent.sessionFetch || !frontOrigin) return null;
|
|
39
|
+
const key = failedKey(agent, frontOrigin);
|
|
40
|
+
const failed = await kvGet(key).catch(() => null);
|
|
41
|
+
const held = letGo && failed?.status === 409;
|
|
42
|
+
if (!askAnyway && !held && failed && Date.now() - failed.at < ASK_AGAIN_MS) return null;
|
|
24
43
|
let res;
|
|
25
44
|
try {
|
|
26
45
|
res = await agent.sessionFetch(`${frontOrigin.replace(/\/$/u, '')}/api/state/open`, {
|
|
@@ -30,9 +49,14 @@ export async function openCopy(agent, frontOrigin, { handle = null, kept = null
|
|
|
30
49
|
if (res.status !== 200) {
|
|
31
50
|
// 404, 409 and 501 are answers (no copy for this account here); anything
|
|
32
51
|
// else is worth saying.
|
|
33
|
-
if (![404, 409, 501].includes(res.status))
|
|
52
|
+
if (![404, 409, 501].includes(res.status)) {
|
|
53
|
+
const why = (await res.json().catch(() => null))?.error;
|
|
54
|
+
agent.log(`the account's copy: the gateway answered ${res.status}${why ? ` (${why})` : ''}`);
|
|
55
|
+
}
|
|
56
|
+
if (REMEMBERED.includes(res.status)) await kvPut(key, { at: Date.now(), status: res.status }).catch(() => {});
|
|
34
57
|
return null;
|
|
35
58
|
}
|
|
59
|
+
if (failed) await kvDel(key).catch(() => {});
|
|
36
60
|
const copy = await res.json().catch(() => null);
|
|
37
61
|
return copy?.base && copy?.token
|
|
38
62
|
? { handle: copy.handle, base: copy.base, token: copy.token, expiresAt: copy.expiresAt, podHome: copy.podHome || null }
|
|
@@ -140,7 +164,7 @@ export async function moveIntoCopy(agent, frontOrigin) {
|
|
|
140
164
|
if (agent.copy) return true;
|
|
141
165
|
await agent.store.commit();
|
|
142
166
|
await agent.lease.release();
|
|
143
|
-
const copy = await openCopy(agent, frontOrigin, { handle: agent.doorKey });
|
|
167
|
+
const copy = await openCopy(agent, frontOrigin, { handle: agent.doorKey, letGo: true });
|
|
144
168
|
if (!copy) {
|
|
145
169
|
if (await agent.lease.acquire()) agent.lease.startRenewal();
|
|
146
170
|
return false;
|