fedipod-server 0.11.0 → 0.12.1

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.
Files changed (142) hide show
  1. package/README.md +15 -6
  2. package/dist/handler.d.ts +6 -0
  3. package/dist/handler.js +23 -10
  4. package/dist/handler.jsonld +4 -0
  5. package/dist/store-pod.js +18 -4
  6. package/lib/{c2s.mjs → client/c2s.mjs} +8 -3
  7. package/lib/{localapi.mjs → client/localapi.mjs} +2 -2
  8. package/lib/client/masto/accounts.mjs +264 -0
  9. package/lib/client/masto/body.mjs +69 -0
  10. package/lib/client/masto/index.mjs +183 -0
  11. package/lib/client/masto/instance.mjs +104 -0
  12. package/lib/client/masto/media.mjs +133 -0
  13. package/lib/client/masto/oauth.mjs +599 -0
  14. package/lib/client/masto/render.mjs +459 -0
  15. package/lib/client/masto/statuses.mjs +331 -0
  16. package/lib/client/masto/timelines.mjs +316 -0
  17. package/lib/{streaming.mjs → client/streaming.mjs} +1 -1
  18. package/lib/{acctfeed.mjs → connections/acctfeed.mjs} +1 -1
  19. package/lib/{atproto.mjs → connections/atproto.mjs} +15 -16
  20. package/lib/{bskygroup.mjs → connections/bskygroup.mjs} +1 -1
  21. package/lib/{fediacct.mjs → connections/fediacct.mjs} +31 -35
  22. package/lib/{import.mjs → connections/import.mjs} +1 -1
  23. package/lib/{tagfeed.mjs → connections/tagfeed.mjs} +3 -3
  24. package/lib/connections/vault.mjs +114 -0
  25. package/lib/core/as2.mjs +124 -0
  26. package/lib/core/contexts/activitystreams.json +379 -0
  27. package/lib/core/contexts/did-v1.json +57 -0
  28. package/lib/core/contexts/fep-5711.json +36 -0
  29. package/lib/core/contexts/gotosocial.json +86 -0
  30. package/lib/core/contexts/identity-v1.json +152 -0
  31. package/lib/core/contexts/index.mjs +45 -0
  32. package/lib/core/contexts/join-lemmy.json +33 -0
  33. package/lib/core/contexts/joinmastodon.json +28 -0
  34. package/lib/core/contexts/map.json +16 -0
  35. package/lib/core/contexts/miscellany.json +19 -0
  36. package/lib/core/contexts/schemaorg.json +8845 -0
  37. package/lib/core/contexts/security-data-integrity-v1.json +78 -0
  38. package/lib/core/contexts/security-data-integrity-v2.json +81 -0
  39. package/lib/core/contexts/security-multikey-v1.json +35 -0
  40. package/lib/core/contexts/security-v1.json +74 -0
  41. package/lib/core/contexts/webfinger.json +10 -0
  42. package/lib/{deliver.mjs → core/deliver.mjs} +2 -2
  43. package/lib/core/intake/activities.mjs +437 -0
  44. package/lib/core/intake/activity.mjs +240 -0
  45. package/lib/core/intake/channel.mjs +144 -0
  46. package/lib/core/intake/group.mjs +222 -0
  47. package/lib/core/intake/index.mjs +629 -0
  48. package/lib/core/intake/notes.mjs +288 -0
  49. package/lib/core/intake/verify.mjs +141 -0
  50. package/lib/{keys.mjs → core/keys.mjs} +1 -1
  51. package/lib/core/publisher/collections.mjs +229 -0
  52. package/lib/core/publisher/index.mjs +421 -0
  53. package/lib/core/publisher/notes.mjs +188 -0
  54. package/lib/core/publisher/questions.mjs +233 -0
  55. package/lib/core/publisher/restore.mjs +196 -0
  56. package/lib/core/shapes/activitystreams.ttl +129 -0
  57. package/lib/core/shapes/index.mjs +107 -0
  58. package/lib/core/shapes/shapes-text.mjs +13 -0
  59. package/lib/{social.mjs → core/social.mjs} +2 -2
  60. package/lib/{store.mjs → core/store.mjs} +4 -0
  61. package/lib/{wire.mjs → core/wire.mjs} +2 -2
  62. package/lib/device/admin/index.mjs +13 -0
  63. package/lib/device/admin/origins.mjs +35 -0
  64. package/lib/device/admin/routes/connections.mjs +144 -0
  65. package/lib/device/admin/routes/gateway.mjs +199 -0
  66. package/lib/device/admin/routes/lifecycle.mjs +191 -0
  67. package/lib/device/admin/routes/owner.mjs +322 -0
  68. package/lib/device/admin/routes/setup.mjs +393 -0
  69. package/lib/device/admin/routes/social.mjs +188 -0
  70. package/lib/device/admin/server.mjs +95 -0
  71. package/lib/device/admin/static.mjs +244 -0
  72. package/lib/device/admin/surface.mjs +274 -0
  73. package/lib/device/cli/commands/account.mjs +586 -0
  74. package/lib/device/cli/commands/run.mjs +278 -0
  75. package/lib/device/cli/commands/service.mjs +221 -0
  76. package/lib/device/cli/commands/setup.mjs +410 -0
  77. package/lib/device/cli/commands/state.mjs +559 -0
  78. package/lib/device/cli/context.mjs +288 -0
  79. package/lib/{migrate.mjs → device/migrate.mjs} +1 -1
  80. package/lib/{remote.mjs → device/remote.mjs} +3 -3
  81. package/lib/{setup.mjs → device/setup.mjs} +3 -3
  82. package/lib/{update.mjs → device/update.mjs} +1 -1
  83. package/lib/{directory.mjs → gateway/directory.mjs} +1 -1
  84. package/lib/{front-core.mjs → gateway/front-core.mjs} +3 -3
  85. package/lib/{gateway-core.mjs → gateway/gateway-core.mjs} +1 -1
  86. package/lib/{httpsig.mjs → gateway/httpsig.mjs} +1 -1
  87. package/lib/{embed.mjs → server/embed.mjs} +149 -22
  88. package/lib/{links.mjs → shared/links.mjs} +1 -1
  89. package/lib/{ua.mjs → shared/ua.mjs} +1 -1
  90. package/package.json +1 -1
  91. package/run-agent.mjs +33 -25
  92. package/web/admin/actors.js +145 -0
  93. package/web/admin/common.js +23 -0
  94. package/web/admin/connections.js +112 -0
  95. package/web/admin/gateway.js +111 -0
  96. package/web/admin/group.js +258 -0
  97. package/web/admin/index.html +7 -1
  98. package/web/admin/record.js +378 -0
  99. package/web/admin/setup/index.html +1 -0
  100. package/web/admin/setup/setup.js +2 -13
  101. package/web/admin/upkeep.js +170 -0
  102. package/web/app/README.md +6 -6
  103. package/web/app/admin-facade.mjs +3 -3
  104. package/web/app/agent.mjs +12 -12
  105. package/web/app/atproto-browser.mjs +1 -1
  106. package/web/app/deliver-relay.mjs +1 -1
  107. package/web/app/dist/sw.js +21684 -5415
  108. package/web/app/dist/sw.js.map +4 -4
  109. package/web/app/fediacct-browser.mjs +1 -1
  110. package/web/app/shims/shapes-text.mjs +8 -0
  111. package/web/app/site/admin/actors.js +145 -0
  112. package/web/app/site/admin/common.js +23 -0
  113. package/web/app/site/admin/connections.js +112 -0
  114. package/web/app/site/admin/gateway.js +111 -0
  115. package/web/app/site/admin/group.js +258 -0
  116. package/web/app/site/admin/index.html +7 -1
  117. package/web/app/site/admin/record.js +378 -0
  118. package/web/app/site/admin/setup/index.html +1 -0
  119. package/web/app/site/admin/setup/setup.js +2 -13
  120. package/web/app/site/admin/upkeep.js +170 -0
  121. package/web/app/site/sw.js +21684 -5415
  122. package/web/app/sw-src.mjs +17 -2
  123. package/lib/admin.mjs +0 -1913
  124. package/lib/intake.mjs +0 -1981
  125. package/lib/mastoapi.mjs +0 -2284
  126. package/lib/publisher.mjs +0 -1192
  127. package/web/admin/admin.js +0 -1181
  128. package/web/app/site/admin/admin.js +0 -1181
  129. /package/lib/{oidc-auth.mjs → client/oidc-auth.mjs} +0 -0
  130. /package/lib/{webpush.mjs → client/webpush.mjs} +0 -0
  131. /package/lib/{bskyfeed.mjs → connections/bskyfeed.mjs} +0 -0
  132. /package/lib/{lease.mjs → core/lease.mjs} +0 -0
  133. /package/lib/{polls.mjs → core/polls.mjs} +0 -0
  134. /package/lib/{proof.mjs → core/proof.mjs} +0 -0
  135. /package/lib/{storage.mjs → core/storage.mjs} +0 -0
  136. /package/lib/{account.mjs → device/account.mjs} +0 -0
  137. /package/lib/{certs.mjs → device/certs.mjs} +0 -0
  138. /package/lib/{export-collections.mjs → device/export-collections.mjs} +0 -0
  139. /package/lib/{home.mjs → device/home.mjs} +0 -0
  140. /package/lib/{ports.mjs → device/ports.mjs} +0 -0
  141. /package/lib/{guard.mjs → shared/guard.mjs} +0 -0
  142. /package/lib/{safefetch.mjs → shared/safefetch.mjs} +0 -0
@@ -3,26 +3,15 @@
3
3
  // at localhost:<port> or at <handle>.localhost:<port>.
4
4
  //
5
5
  // External file, not an inline script: the CSP allows 'self' plus the hashes
6
- // of Phanpy's own inline bootstrap, and nothing else.
6
+ // of Phanpy's own inline bootstrap, and nothing else. `$`, `BASE`, `api` and
7
+ // `postJson` come from ../common.js, loaded first.
7
8
 
8
- const $ = (id) => document.getElementById(id);
9
9
  // Empty means gone, not a blank line where a sentence used to be.
10
10
  const strap = (t) => { const el = $('strap'); el.textContent = t || ''; el.hidden = !t; };
11
11
  // By id, not by position: these were `body > section` until a wrapper went
12
12
  // round them for layout, and the selector then matched nothing — every pane
13
13
  // kept whatever it started as and the page sat on "Reading this agent's state".
14
14
  const show = (id) => { for (const s of document.querySelectorAll('section[id^="pane-"]')) s.hidden = s.id !== id; };
15
- // The door this page is served behind: nothing when the agent runs on this
16
- // machine, `/app` when the identity is hosted by its own pod server. Read from
17
- // the page's own address, so one build serves both.
18
- const BASE = location.pathname.replace(/\/admin\/.*$/u, '');
19
- const api = async (path, init) => {
20
- const res = await fetch(BASE + path, { ...init, headers: { ...(init?.headers || {}), 'x-fedipod-page': '1' } });
21
- return { status: res.status, json: await res.json().catch(() => null) };
22
- };
23
- const postJson = (path, body) => api(path, {
24
- method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body),
25
- });
26
15
 
27
16
  let state = null;
28
17
 
@@ -0,0 +1,170 @@
1
+ // upkeep.js — upkeep and the lifecycle: the output pane, drain, recover,
2
+ // log and dead letters; the confirmations for rotate, retire and move; and
3
+ // the inbox backlog panel.
4
+
5
+ // Which button filled the output pane, so clicking that one again closes it
6
+ // rather than re-fetching the same thing under an already-open panel.
7
+ let outputSource = null;
8
+
9
+ const OUTPUT_TITLES = { log: 'Log', deadletter: 'Dead letters', drain: 'Inbox drain', rebuild: 'Recovered posts' };
10
+ const output = (obj, source = null) => {
11
+ closePanels('output');
12
+ outputSource = source;
13
+ solWindow.show('output', OUTPUT_TITLES[source] || 'Output');
14
+ $('output').textContent = typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2);
15
+ };
16
+
17
+ const showingFrom = (source) => outputSource === source && solWindow.openId() === 'output';
18
+
19
+ // Drain is the one that does work rather than reveals it, so a second click
20
+ // re-runs instead of closing. It can take a while — the agent joins a sweep
21
+ // already in flight and queues another after it — and a button that looks dead
22
+ // for a minute reads as broken.
23
+ $('do-drain').addEventListener('click', async (ev) => {
24
+ const b = ev.currentTarget;
25
+ b.disabled = true;
26
+ b.textContent = 'draining…';
27
+ say('draining the inbox — if a sweep is already running this waits for it to finish');
28
+ const r = await write('/drain', {}, 'inbox drained');
29
+ b.disabled = false;
30
+ b.textContent = 'Drain the inbox';
31
+ if (r) {
32
+ const box = r.inbox || {};
33
+ say(`inbox drained — ${box.count ?? 0} still waiting`);
34
+ output(r, 'drain');
35
+ }
36
+ });
37
+
38
+ // Like the drain, this does work rather than reveals it, so a second click
39
+ // re-runs. Nothing here can lose anything: it only adds posts back.
40
+ $('do-rebuild').addEventListener('click', async (ev) => {
41
+ const b = ev.currentTarget;
42
+ b.disabled = true;
43
+ b.textContent = 'recovering…';
44
+ say('reading what the pod still holds — one request per post, so this takes a moment');
45
+ const r = await write('/rebuild', {}, 'checked');
46
+ b.disabled = false;
47
+ b.textContent = 'Recover posts';
48
+ if (!r) return;
49
+ if (r.why) { say(r.why, 'err'); return; }
50
+ if (!r.landed) { say('recovered posts could NOT be saved — see the log', 'err'); return; }
51
+ say(r.recovered
52
+ ? `recovered ${r.recovered} post(s) the pod had and this machine did not`
53
+ : `nothing was missing — the pod indexed ${r.indexed} post(s), all of them already here`);
54
+ output(r, 'rebuild');
55
+ });
56
+
57
+ $('do-log').addEventListener('click', async () => {
58
+ if (showingFrom('log')) { closePanels(); return; }
59
+ const { json } = await api('/log');
60
+ output((json?.lines || []).slice(-60).join('\n') || 'nothing logged yet', 'log');
61
+ });
62
+
63
+ $('do-deadletter').addEventListener('click', async () => {
64
+ if (showingFrom('deadletter')) { closePanels(); return; }
65
+ const { json } = await api('/deadletter');
66
+ output(json?.items?.length ? json.items : 'no dead letters', 'deadletter');
67
+ });
68
+
69
+ // ---- lifecycle ----
70
+ // None of these can be taken back by clicking again, so the button only opens
71
+ // the matching warning in the markup; the second click is the one that acts.
72
+ // Retire also wants the handle typed, because a misclick cannot produce it.
73
+
74
+ const LIFECYCLE = {
75
+ 'rotate-key': { path: '/rotate-key', title: 'Rotate the signing key', done: (r) => (r.changed ? 'rotated and republished' : 'no change — the key was already fresh') },
76
+ retire: { path: '/retire', title: 'Retire this identity', go: 'Retire it', danger: true, done: (r) => `retired ${r.deletedAt}: Delete delivered to ${r.inboxes} inbox(es)` },
77
+ move: { path: '/move', title: 'Transfer this account away', go: 'Transfer it', focus: 'move-target',
78
+ done: (r) => `transferred to ${r.target}: Move delivered to ${r.inboxes} inbox(es), unfollowed ${r.unfollowed}/${r.following}` },
79
+ };
80
+ let pending = null;
81
+
82
+ const closeConfirm = () => closePanels();
83
+
84
+ for (const btn of document.querySelectorAll('[data-confirm]')) {
85
+ btn.addEventListener('click', () => {
86
+ const what = btn.dataset.confirm;
87
+ // The same button again closes its question rather than re-asking it.
88
+ if (pending === what && solWindow.openId() === 'confirm-form') { closePanels(); return; }
89
+ closePanels(); // including whatever else was open
90
+ pending = what;
91
+ const spec = LIFECYCLE[what];
92
+ $(`warn-${what}`).hidden = false;
93
+ solWindow.show('confirm-form', spec.title);
94
+ $('confirm-go').className = spec.danger ? 'danger' : 'primary';
95
+ $('confirm-go').textContent = spec.go || 'Confirm';
96
+ if (spec.focus) $(spec.focus).focus();
97
+ else if (what === 'retire') $('confirm-handle').focus();
98
+ });
99
+ }
100
+
101
+ // Offered from inside the retire warning: someone reading it has already said
102
+ // what they want ("not this account, here, any more") and these are the two
103
+ // answers that are not destruction. Switching panels rather than closing means
104
+ // they do not have to go and find the button themselves.
105
+ const openConfirm = (what) => {
106
+ closePanels(); // or `show` toggles: same panel, different warning
107
+ document.querySelector(`[data-confirm="${what}"]`).click();
108
+ };
109
+ // Park lives on the status control now; from inside the retire warning it is
110
+ // still one click — close the question and park.
111
+ $('go-park').addEventListener('click', () => { closePanels(); setStatus(true); });
112
+ $('go-move').addEventListener('click', () => openConfirm('move'));
113
+
114
+ $('confirm-cancel').addEventListener('click', () => { closeConfirm(); say('nothing changed'); });
115
+
116
+ $('confirm-form').addEventListener('submit', async (ev) => {
117
+ ev.preventDefault();
118
+ if (!pending) return;
119
+ const what = pending;
120
+ const body = what === 'retire' ? { confirm: $('confirm-handle').value.trim() }
121
+ : what === 'move' ? { target: $('move-target').value.trim(), confirm: $('confirm-handle-move').value.trim() }
122
+ // Only where the field is shown (the browser build — see index.html).
123
+ // On the Node agent the row stays hidden and nothing is sent, which is
124
+ // what that agent expects.
125
+ : what === 'rotate-key' && !$('rotate-pw-row').hidden
126
+ ? { password: $('rotate-password').value }
127
+ : {};
128
+ if (what === 'move' && !body.target) { say('name the account to transfer to', 'err'); return; }
129
+ $('confirm-go').disabled = true;
130
+ say(`${what} — this talks to the pod and to other servers, so it takes a moment`);
131
+ const r = await write(LIFECYCLE[what].path, body, what);
132
+ $('confirm-go').disabled = false;
133
+ if (!r) return; // write() already said why
134
+ closeConfirm();
135
+ say(LIFECYCLE[what].done(r));
136
+ load(); // mode, and whether it is retired, both changed
137
+ });
138
+
139
+ // ---- inbox ----
140
+ // Only appears when there is enough waiting to be worth a decision. The agent
141
+ // drains oldest-first regardless; this exists to let the owner say "do not
142
+ // bother with that fortnight", which is not a call an agent should make on
143
+ // someone's mail by itself.
144
+ const INBOX_PROMPT_AT = 500;
145
+ let dismissed = false;
146
+
147
+ async function renderInbox() {
148
+ if (dismissed) return;
149
+ const { json: st } = await api('/status');
150
+ const box = st?.inbox;
151
+ const panel = $('pane-inbox');
152
+ if (!box || box.count < INBOX_PROMPT_AT) { panel.hidden = true; return; }
153
+ const mb = box.bytes >= 1048576
154
+ ? `${(box.bytes / 1048576).toFixed(1)} MB` : `${Math.round(box.bytes / 1024)} kB`;
155
+ const since = box.oldest ? new Date(box.oldest).toLocaleDateString() : 'unknown';
156
+ $('inbox-summary').textContent =
157
+ `${box.count.toLocaleString()} deliveries waiting (${mb}), the oldest from ${since}.`;
158
+ // One request each to read and delete, and the agent holds itself to 60 a
159
+ // minute, so the honest number is minutes not seconds.
160
+ $('inbox-warn').hidden = box.count < 2000;
161
+ $('inbox-warn').textContent = box.count >= 2000
162
+ ? `At 60 requests a minute this is roughly ${Math.ceil(box.count * 2 / 60)} minutes of `
163
+ + 'draining if you keep everything. Discarding the old content is much quicker.'
164
+ : '';
165
+ panel.hidden = false;
166
+ }
167
+
168
+ // The gateway, as a facts row under software: attach through a multi-user
169
+ // front with this agent's own credential, detach back to the pod inbox. The
170
+ // forms live in the floating window, like every other disclosure.
package/web/app/README.md CHANGED
@@ -5,13 +5,13 @@ See `claude/plans/browser-agent.md` for the whole design and status.
5
5
 
6
6
  | file | what |
7
7
  |---|---|
8
- | `pod-auth.mjs` | The pod side of sign-in, browser-native: create a CSS account + pod, mint a client credential, and a DPoP-bound `fetch` that writes to the pod. The twin of `lib/account.mjs` + `vendor/idp-grant.cjs`. |
8
+ | `pod-auth.mjs` | The pod side of sign-in, browser-native: create a CSS account + pod, mint a client credential, and a DPoP-bound `fetch` that writes to the pod. The twin of `lib/device/account.mjs` + `vendor/idp-grant.cjs`. |
9
9
  | `keystore.mjs` | WebCrypto RSA/Ed25519 key generation, and wrapping the keys under the account password (PBKDF2-SHA256 + AES-GCM-256). The pod holds only the wrapped form, so the pod's host cannot sign as you. |
10
10
  | `keys-browser.mjs` | Importing a keys record for signing, and finding one: this browser's opened copy in IndexedDB first, else the pod's. A wrapped one the browser has not opened yet raises `KeyPasswordNeeded`, which `boot.mjs` answers with the unlock pane — once per browser. |
11
11
  | `signup.mjs` | The `fedipod setup` flow, in the browser, up to publish: account, pod, credential, keys locked on the pod (owner-only ACL written *before* the key). Produces the credential/keys/config shapes the agent already reads. |
12
12
  | `shims/fedify-sig.mjs` | Browser stand-in for `@fedify/fedify/sig` (which will not bundle for a browser). `sign()` returns signed headers as data for the relay; `signRequest()` wraps it Fedify-shaped. Proven byte-identical to Fedify. |
13
13
  | `shims/node-crypto.mjs` | Browser stand-in for `node:crypto` — the small synchronous slice the agent uses, via crypto-browserify, plus native WebCrypto. |
14
- | `shims/safefetch.mjs` | Browser stand-in for `lib/safefetch.mjs`. Pinning and the private-address checks are unnecessary here (a browser closes DNS rebinding itself); the BYTE BUDGET is not, so `readCapped` streams and stops at the cap exactly as the Node one does. |
14
+ | `shims/safefetch.mjs` | Browser stand-in for `lib/shared/safefetch.mjs`. Pinning and the private-address checks are unnecessary here (a browser closes DNS rebinding itself); the BYTE BUDGET is not, so `readCapped` streams and stops at the cap exactly as the Node one does. |
15
15
  | `dist/` | The bundled agent, built by `scripts/build-app.mjs`. Committed like `phanpy/dist`, regenerated on release. (Not present until the agent entry is built.) |
16
16
 
17
17
  Build: `node scripts/build-app.mjs`. Tests live in `claude/validation/`:
@@ -39,12 +39,12 @@ worker answers the data endpoints it calls. See
39
39
 
40
40
  | file | what |
41
41
  |---|---|
42
- | `admin-facade.mjs` | Answers the owner/manage endpoints (`/status`, `/config`, `/gateway`, `/alias`, `/rotate-key`, `/rebuild`, `/move`, `/retire`, `/inbox/prune`, `/deadletter`, `/blocks`, `/atproto*`, `/fediacct*`) over the browser agent, mirroring `lib/admin.mjs`. Personal only. |
43
- | `atproto-browser.mjs` | The Bluesky connection (`lib/atproto.mjs`) with a per-connection storage choice — IndexedDB (this browser) or owner-only pod state — plus pause. |
44
- | `fediacct-browser.mjs` | Connections to fediverse accounts on other servers (`lib/fediacct.mjs`): the OAuth dance, the same storage choice, and a best-effort server-side revoke on disconnect. |
42
+ | `admin-facade.mjs` | Answers the owner/manage endpoints (`/status`, `/config`, `/gateway`, `/alias`, `/rotate-key`, `/rebuild`, `/move`, `/retire`, `/inbox/prune`, `/deadletter`, `/blocks`, `/atproto*`, `/fediacct*`) over the browser agent, mirroring `lib/device/admin.mjs`. Personal only. |
43
+ | `atproto-browser.mjs` | The Bluesky connection (`lib/connections/atproto.mjs`) with a per-connection storage choice — IndexedDB (this browser) or owner-only pod state — plus pause. |
44
+ | `fediacct-browser.mjs` | Connections to fediverse accounts on other servers (`lib/connections/fediacct.mjs`): the OAuth dance, the same storage choice, and a best-effort server-side revoke on disconnect. |
45
45
  | `idb-kv.mjs` | The per-origin IndexedDB key/value store the two connectors use for "on this device, never the pod" credentials. |
46
46
 
47
- `agent.mjs` also holds the single-active-agent **lease** (`lib/lease.mjs`) — a
47
+ `agent.mjs` also holds the single-active-agent **lease** (`lib/core/lease.mjs`) — a
48
48
  second device runs read-only until it takes over — and starts the drain/mirrors
49
49
  only when it is the active holder.
50
50
 
@@ -14,10 +14,10 @@
14
14
  //
15
15
  // It mirrors lib/admin.mjs's handlers for those paths, calling the same agent
16
16
  // objects (store, publisher, intake, deliverer, remote) the Node agent does.
17
- import { publicHandle, webfingerHost } from '../../lib/wire.mjs';
17
+ import { publicHandle, webfingerHost } from '../../lib/core/wire.mjs';
18
18
  import * as podInbox from '../../lib/pod/inbox.mjs';
19
- import { normalizeImport, IMPORT_KINDS } from '../../lib/import.mjs';
20
- import { hashPassword } from '../../lib/mastoapi.mjs';
19
+ import { normalizeImport, IMPORT_KINDS } from '../../lib/connections/import.mjs';
20
+ import { hashPassword } from '../../lib/client/masto/index.mjs';
21
21
 
22
22
  // The identity itself — changing any means a different actor, i.e. a new setup.
23
23
  const PERMANENT_CONFIG = ['handle', 'remotePod', 'issuer', 'root', 'kind'];
package/web/app/agent.mjs CHANGED
@@ -5,16 +5,16 @@
5
5
  // the signing key comes from WebCrypto (keys-browser), and delivery goes through
6
6
  // the relay (deliver-relay). Everything between — wire, the store, the
7
7
  // publisher, intake, the Mastodon facade — is lib/, unchanged.
8
- import { apUrls } from '../../lib/wire.mjs';
8
+ import { apUrls } from '../../lib/core/wire.mjs';
9
9
  import * as containers from '../../lib/pod/containers.mjs';
10
10
  import * as podState from '../../lib/pod/state.mjs';
11
- import { PodStore } from '../../lib/store.mjs';
12
- import { HttpStorage } from '../../lib/storage.mjs';
13
- import { Publisher } from '../../lib/publisher.mjs';
14
- import { Intake } from '../../lib/intake.mjs';
15
- import { Lease } from '../../lib/lease.mjs';
16
- import { MastoApi } from '../../lib/mastoapi.mjs';
17
- import { TagFeed } from '../../lib/tagfeed.mjs';
11
+ import { PodStore } from '../../lib/core/store.mjs';
12
+ import { HttpStorage } from '../../lib/core/storage.mjs';
13
+ import { Publisher } from '../../lib/core/publisher/index.mjs';
14
+ import { Intake } from '../../lib/core/intake/index.mjs';
15
+ import { Lease } from '../../lib/core/lease.mjs';
16
+ import { MastoApi } from '../../lib/client/masto/index.mjs';
17
+ import { TagFeed } from '../../lib/connections/tagfeed.mjs';
18
18
  import { makeDpopSession } from './pod-auth.mjs';
19
19
  import { BrowserRemotePod } from './pod-remote.mjs';
20
20
  import { importSigningKey, loadKeysFromPod, keyCacheKey } from './keys-browser.mjs';
@@ -23,11 +23,11 @@ import { kvPut } from './idb-kv.mjs';
23
23
  import { RelayDeliverer } from './deliver-relay.mjs';
24
24
  import { AdminFacade } from './admin-facade.mjs';
25
25
  import { BrowserAtproto } from './atproto-browser.mjs';
26
- import { BskyFeed } from '../../lib/bskyfeed.mjs';
26
+ import { BskyFeed } from '../../lib/connections/bskyfeed.mjs';
27
27
  import { BrowserFediAccounts } from './fediacct-browser.mjs';
28
- import { AcctFeed } from '../../lib/acctfeed.mjs';
29
- import { followActor, unfollowActor } from '../../lib/social.mjs';
30
- import { ImportWorker } from '../../lib/import.mjs';
28
+ import { AcctFeed } from '../../lib/connections/acctfeed.mjs';
29
+ import { followActor, unfollowActor } from '../../lib/core/social.mjs';
30
+ import { ImportWorker } from '../../lib/connections/import.mjs';
31
31
 
32
32
  // The authorities this identity answers on: exactly one, this origin. The Node
33
33
  // agent gets this from lib/guard.mjs, which is not in the browser bundle and
@@ -10,7 +10,7 @@
10
10
  // 2. The mirror can be paused (feedPaused) without disconnecting.
11
11
  //
12
12
  // Bluesky's API answers CORS, so the fetches go direct, not through the relay.
13
- import { Atproto } from '../../lib/atproto.mjs';
13
+ import { Atproto } from '../../lib/connections/atproto.mjs';
14
14
  import { kvGet, kvPut, kvDel } from './idb-kv.mjs';
15
15
 
16
16
  const IDB_KEY = 'atproto';
@@ -7,7 +7,7 @@
7
7
  // which sends it verbatim. Everything else — the retry queue, the cooling
8
8
  // hosts, the dead-letter, FEP-8b32 proofs — is the Node Deliverer, reused by
9
9
  // overriding only the one network step.
10
- import { Deliverer } from '../../lib/deliver.mjs';
10
+ import { Deliverer } from '../../lib/core/deliver.mjs';
11
11
  import { sign } from './shims/fedify-sig.mjs';
12
12
 
13
13
  export class RelayDeliverer extends Deliverer {