@solarpunkltd/swarm-id 0.0.0-stage → 0.8.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 (111) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +89 -2
  3. package/dist/bus/account-bus.d.ts +104 -0
  4. package/dist/bus/account-delta.d.ts +52 -0
  5. package/dist/bus/bus-context.d.ts +7 -0
  6. package/dist/bus/envelope.d.ts +9 -0
  7. package/dist/bus/messages.d.ts +241 -0
  8. package/dist/bus/presence.d.ts +62 -0
  9. package/dist/bus/signaling-transport.d.ts +79 -0
  10. package/dist/chunk/bmt.d.ts +16 -0
  11. package/dist/chunk/cac.d.ts +17 -0
  12. package/dist/chunk/constants.d.ts +10 -0
  13. package/dist/chunk/encrypted-cac.d.ts +47 -0
  14. package/dist/chunk/encryption.d.ts +85 -0
  15. package/dist/chunk/index.d.ts +5 -0
  16. package/dist/chunks/chat-binding-DO5aGhPl.js +23 -0
  17. package/dist/chunks/chat-binding-DO5aGhPl.js.map +1 -0
  18. package/dist/errors.d.ts +35 -0
  19. package/dist/index.d.ts +27 -0
  20. package/dist/internal.d.ts +49 -0
  21. package/dist/internal.esm.js +2 -0
  22. package/dist/internal.esm.js.map +1 -0
  23. package/dist/proxy/act/act.d.ts +58 -0
  24. package/dist/proxy/act/crypto.d.ts +46 -0
  25. package/dist/proxy/act/grantee-list.d.ts +81 -0
  26. package/dist/proxy/act/history.d.ts +182 -0
  27. package/dist/proxy/act/index.d.ts +114 -0
  28. package/dist/proxy/app-stamp-limits.d.ts +62 -0
  29. package/dist/proxy/chunk-upload-stream.d.ts +37 -0
  30. package/dist/proxy/chunking.d.ts +15 -0
  31. package/dist/proxy/collection.d.ts +38 -0
  32. package/dist/proxy/download-data.d.ts +27 -0
  33. package/dist/proxy/errors.d.ts +8 -0
  34. package/dist/proxy/feed-manifest.d.ts +60 -0
  35. package/dist/proxy/feeds/epochs/async-finder.d.ts +70 -0
  36. package/dist/proxy/feeds/epochs/epoch.d.ts +79 -0
  37. package/dist/proxy/feeds/epochs/finder.d.ts +60 -0
  38. package/dist/proxy/feeds/epochs/index.d.ts +30 -0
  39. package/dist/proxy/feeds/epochs/types.d.ts +110 -0
  40. package/dist/proxy/feeds/epochs/updater.d.ts +76 -0
  41. package/dist/proxy/feeds/epochs/utils.d.ts +21 -0
  42. package/dist/proxy/feeds/index.d.ts +4 -0
  43. package/dist/proxy/feeds/sequence/async-finder.d.ts +14 -0
  44. package/dist/proxy/feeds/sequence/finder.d.ts +11 -0
  45. package/dist/proxy/feeds/sequence/index.d.ts +22 -0
  46. package/dist/proxy/feeds/sequence/types.d.ts +82 -0
  47. package/dist/proxy/feeds/sequence/updater.d.ts +20 -0
  48. package/dist/proxy/index.d.ts +5 -0
  49. package/dist/proxy/manifest-builder.d.ts +164 -0
  50. package/dist/proxy/mantaray.d.ts +76 -0
  51. package/dist/proxy/soc-restamp-slots.d.ts +48 -0
  52. package/dist/proxy/stamp-chunk.d.ts +45 -0
  53. package/dist/proxy/stamp-worker-handler.d.ts +32 -0
  54. package/dist/proxy/stamp-worker-pool.d.ts +52 -0
  55. package/dist/proxy/stamp-worker.d.ts +1 -0
  56. package/dist/proxy/types.d.ts +38 -0
  57. package/dist/proxy/upload.d.ts +207 -0
  58. package/dist/schemas.d.ts +671 -0
  59. package/dist/stamp-worker.iife.js +1 -0
  60. package/dist/storage/debounced-uploader.d.ts +61 -0
  61. package/dist/storage/utilization-store.d.ts +113 -0
  62. package/dist/swarm-id-client.d.ts +1143 -0
  63. package/dist/swarm-id-proxy.d.ts +1079 -0
  64. package/dist/swarm-id.esm.js +2 -0
  65. package/dist/swarm-id.esm.js.map +1 -0
  66. package/dist/sync/batch-write-coordinator.d.ts +348 -0
  67. package/dist/sync/device-roster.d.ts +59 -0
  68. package/dist/sync/device-state.d.ts +199 -0
  69. package/dist/sync/fold-account-from-swarm.d.ts +53 -0
  70. package/dist/sync/index.d.ts +11 -0
  71. package/dist/sync/merge-snapshot.d.ts +57 -0
  72. package/dist/sync/partition-intent.d.ts +218 -0
  73. package/dist/sync/partition-lease.d.ts +531 -0
  74. package/dist/sync/partition-lock.d.ts +218 -0
  75. package/dist/sync/partition-state.d.ts +287 -0
  76. package/dist/sync/session-check.d.ts +29 -0
  77. package/dist/sync/store-interfaces.d.ts +48 -0
  78. package/dist/sync/sync-account.d.ts +45 -0
  79. package/dist/sync/timing-constants.d.ts +32 -0
  80. package/dist/sync/types.d.ts +18 -0
  81. package/dist/types.d.ts +3042 -0
  82. package/dist/utils/account-state-snapshot.d.ts +43 -0
  83. package/dist/utils/active-devices.d.ts +45 -0
  84. package/dist/utils/avatar.d.ts +30 -0
  85. package/dist/utils/batch-utilization.d.ts +840 -0
  86. package/dist/utils/batch-write-lock.d.ts +12 -0
  87. package/dist/utils/bee-error.d.ts +11 -0
  88. package/dist/utils/chat-binding.d.ts +113 -0
  89. package/dist/utils/coalesced-task.d.ts +28 -0
  90. package/dist/utils/collection.d.ts +6 -0
  91. package/dist/utils/connection-info.d.ts +11 -0
  92. package/dist/utils/constants.d.ts +28 -0
  93. package/dist/utils/device-id.d.ts +109 -0
  94. package/dist/utils/hex.d.ts +31 -0
  95. package/dist/utils/json-rpc.d.ts +34 -0
  96. package/dist/utils/key-derivation.d.ts +124 -0
  97. package/dist/utils/lock-soc.d.ts +35 -0
  98. package/dist/utils/postage-contract.d.ts +143 -0
  99. package/dist/utils/postage-stamp-association.d.ts +39 -0
  100. package/dist/utils/promise.d.ts +37 -0
  101. package/dist/utils/sealed-values.d.ts +23 -0
  102. package/dist/utils/seed-encryption.d.ts +17 -0
  103. package/dist/utils/site-allow-list.d.ts +54 -0
  104. package/dist/utils/stamp-lifespan.d.ts +37 -0
  105. package/dist/utils/storage-managers.d.ts +62 -0
  106. package/dist/utils/storage-probe.d.ts +40 -0
  107. package/dist/utils/tag.d.ts +11 -0
  108. package/dist/utils/ttl.d.ts +120 -0
  109. package/dist/utils/url.d.ts +55 -0
  110. package/dist/utils/versioned-storage.d.ts +183 -0
  111. package/package.json +91 -3
@@ -0,0 +1,1079 @@
1
+ import type { SiteAllowList } from "./utils/site-allow-list";
2
+ /**
3
+ * Debounce window for proxy-side account-state publishing. Coalesces a burst of
4
+ * triggers (lease acquisition + storage changes) into a single feed write.
5
+ */
6
+ export declare const PUBLISH_DEBOUNCE_MS = 1500;
7
+ /**
8
+ * Swarm ID Proxy - Runs inside the iframe
9
+ *
10
+ * Responsibilities:
11
+ * - Receive app-specific secrets from auth popup
12
+ * - Keep a partitioned session in this partition's own localStorage (#635)
13
+ * - Proxy Bee API calls from parent dApp
14
+ * - Augment requests with authentication
15
+ * - Return responses to parent dApp
16
+ */
17
+ export declare class SwarmIdProxy {
18
+ private parentOrigin;
19
+ private parentIdentified;
20
+ /**
21
+ * Set by the first `parentIdentify`, before its allow-list check awaits, so a
22
+ * second one cannot start a check of its own. A refused parent leaves it set:
23
+ * the frame answers nothing more until the page loads it again.
24
+ */
25
+ private parentIdentifyReceived;
26
+ private siteAllowList;
27
+ private authenticated;
28
+ private authLoading;
29
+ private appSecret;
30
+ /**
31
+ * The chat binding the popup handed over with this session, already checked
32
+ * against it (`acceptHandedOverChatBinding`). Only a handover sets it: an
33
+ * unpartitioned session reads its connection out of shared storage and
34
+ * reports none.
35
+ */
36
+ private chatBinding;
37
+ private postageBatchId;
38
+ private signerKey;
39
+ private stamper;
40
+ /**
41
+ * Hash of `<owner>-<encryptionKey>` that the current `stamper` was built
42
+ * with. Account-level inputs are baked into `UtilizationAwareStamper` at
43
+ * construction, so when the underlying account changes (e.g. a local
44
+ * account migrates to a synced one) we need to detect that even if the
45
+ * postage stamp's batch/signer didn't change, and rebuild the stamper.
46
+ */
47
+ private stamperAccountFingerprint;
48
+ private stampWorkerPool;
49
+ private storagePartitioned;
50
+ private pendingChallenge;
51
+ /**
52
+ * Hydrated account view for the storage-partitioning fallback: the synced
53
+ * projection handed over by the connect popup (`AuthData.account`), held in
54
+ * memory only — the stored-account schema requires a vault. What survives a
55
+ * reload is the handover itself, under its own key (#635), which this view
56
+ * is then rebuilt from. When set, the proxy is a
57
+ * first-class writer despite the partition (docs/Account-Bus.md, phase 3).
58
+ */
59
+ private partitionAccount;
60
+ /** Account-derived topic the attached bus transports share; undefined when
61
+ * none are attached. */
62
+ private busTopic;
63
+ private removeBusLocal;
64
+ private removeBusSignaling;
65
+ /** Derivation key of a join that attached everything it wanted. Lets the
66
+ * synchronous `joinAccountBus` return without re-deriving, and — because it
67
+ * stays unset when a transport failed to attach — makes the next join a
68
+ * RETRY rather than a dedup'd no-op. */
69
+ private busJoinedKey;
70
+ /** Bumped by every bus join and by `clearAuthData`, so a join whose key
71
+ * derivation is still in flight can tell it has been superseded. */
72
+ private busJoinGeneration;
73
+ /** Account whose room the attached transports currently speak into. A
74
+ * transport encrypts with its construction-time key, so this — not whichever
75
+ * connection resolves now — is who a publish actually reaches. */
76
+ private busBoundAccountId;
77
+ /** Scheduled answers to peers' `lease-request`s, by request id, so a peer
78
+ * earlier in the rank order can call ours off (`yieldRankDelayMs`). */
79
+ private pendingYields;
80
+ /** Request ids somebody has claimed (us or a peer). Insertion-ordered and
81
+ * capped at `ANSWERED_REQUEST_MEMORY`. Separate from `pendingYields`
82
+ * because the cancel window has to outlive the rank timer: the timer only
83
+ * starts the yield, whose first Swarm write is still ahead of it. */
84
+ private answeredRequests;
85
+ /**
86
+ * Utilization deltas that arrived while the stamper had no lane, held until
87
+ * a bind names one (`applyPendingLaneUpdate`). Keyed by lane so a delta for
88
+ * a lane we do not end up binding cannot displace the one we do — the point
89
+ * of buffering is that nothing is silently lost. Buckets merge per index
90
+ * with `max`, matching `applyUtilizationUpdate`'s own monotonic rule.
91
+ * Bounded by the account's partition count.
92
+ */
93
+ private pendingLaneUpdates;
94
+ /**
95
+ * The newest timestamp this frame gave a stamp again of a single-owner
96
+ * chunk, in milliseconds, by site, stamp and chunk address. Set under the
97
+ * write lock when the stamp is made, while the stored slot record is
98
+ * written only after the lock, so a second stamp of that address inside
99
+ * the lock still gets a newer timestamp than the first.
100
+ */
101
+ private lastRestampMs;
102
+ private utilizationStore;
103
+ /** The Bee node the person set in Swarm ID's network settings. */
104
+ private ownBeeApiUrl;
105
+ /**
106
+ * The Bee node the embedding site named for its own session, from
107
+ * `parentIdentify` or `setBeeApiUrl`. In memory only: a frame
108
+ * serves the one parent origin it was identified by, so this is that
109
+ * site's alone, and nothing writes it to storage, the account or a sync
110
+ * feed. The site sends it again on every load.
111
+ */
112
+ private siteBeeApiUrl;
113
+ /**
114
+ * The subsidised gateway the site asked for, kept apart from
115
+ * `subsidisedGatewayUrl`, which the person's own custom node can switch
116
+ * off, so the gateway can come back once the site names its own node.
117
+ */
118
+ private siteSubsidisedGatewayUrl;
119
+ private gnosisRpcUrl;
120
+ private postageStampContractAddress;
121
+ private signalingUrl;
122
+ private authButtonContainer;
123
+ private buttonConfig;
124
+ private popupMode;
125
+ private appMetadata;
126
+ /**
127
+ * Bee clients by the URL they were asked for. Keyed on that input URL, not
128
+ * on the client's own `url`, which bee-js keeps without the trailing slash.
129
+ */
130
+ private beeClients;
131
+ private unsubscribeStorageListeners;
132
+ private storageWorkQueue;
133
+ private lastConnectionInfo;
134
+ private isConnecting;
135
+ private parentWindow;
136
+ private bus;
137
+ /** Who else is live in the account's room, from their `presence` beats. */
138
+ private presence;
139
+ private presenceTimer;
140
+ private subsidisedGatewayUrl;
141
+ /**
142
+ * The resolved stamp's stored lifetime fields (#745), set wherever the
143
+ * stamp is. Expiry is derived from them on every read, so a tab left open
144
+ * past the drive's lifetime refuses its own writes rather than letting Bee
145
+ * refuse the lease claim.
146
+ */
147
+ private stampLifetime;
148
+ /** Bumped by every `initializeStamper`; an older init sees it move and stops */
149
+ private stamperInitGeneration;
150
+ /** Why the session refuses to stamp with the resolved drive, if it does. */
151
+ private get stampRefusal();
152
+ /**
153
+ * The node the site's own content goes through: the site's address when it
154
+ * named one, the person's setting otherwise. Content only, the reads and
155
+ * stamped uploads the site asks for. Nothing that decides whether this
156
+ * session may write, or that coordinates the person's devices, reads it
157
+ * (`accountBee`), because a site could answer those from a node of its own.
158
+ */
159
+ private get beeApiUrl();
160
+ /**
161
+ * Switch off the site's subsidised gateway when the node in effect is the
162
+ * person's own custom one, so their uploads go to the node they chose. A
163
+ * node the site named is not the person's choice, and the site asked for
164
+ * both, so it keeps the gateway.
165
+ */
166
+ private dropGatewayForOwnCustomNode;
167
+ /**
168
+ * The client for the node the current mode writes to: the dApp's gateway
169
+ * while the session is subsidised, the configured node otherwise. Reads have
170
+ * to come from where the uploads go, or a dApp reads back a 404 for the
171
+ * chunk it just wrote.
172
+ *
173
+ * Derived on every read rather than assigned, because a mode change is not
174
+ * always an event — a drive's expiry is read off the clock — and a client
175
+ * picked once keeps pointing wherever the session started: at the gateway
176
+ * for a session that connected after the page loaded, or at the node for
177
+ * one whose drive has since run out or been removed.
178
+ */
179
+ private get bee();
180
+ /**
181
+ * The client for the site's content node, whatever the mode: where the
182
+ * site's stamped uploads go in user-stamp mode, which `bee` also reads from
183
+ * then.
184
+ */
185
+ private get nodeBee();
186
+ /**
187
+ * The client for the person's own node, whatever the site named. The
188
+ * coordinator's lock, lease and state chunks, the device roster and the
189
+ * restored session's revocation check go through it: they decide what this
190
+ * session may do with the person's account and stamp, so the embedding
191
+ * site must not be able to answer them.
192
+ */
193
+ private get accountBee();
194
+ /**
195
+ * A client for `url`, kept per URL so the content, account and gateway
196
+ * clients do not rebuild each other. Bounded, because a site can name a
197
+ * new address at any time.
198
+ */
199
+ private beeClientFor;
200
+ /**
201
+ * The write path (lock + partition lease + stamp flush) for the current
202
+ * account+batch. Assigned in `initializeStamper` together with the stamper it
203
+ * writes through, and dropped with it whenever the resolved stamp changes
204
+ * (`setResolvedStamp`); undefined before auth / after disconnect. The proxy
205
+ * delegates all writes to it via `withModeAwareWriteLock`.
206
+ */
207
+ private coordinator;
208
+ /**
209
+ * Debounce timer + in-flight guard for proxy-side account-state publishing.
210
+ * The proxy publishes the account snapshot to the shared sync feed when it
211
+ * first acquires a partition (so the device announces itself — see #336
212
+ * motivation #4) and when account state changes while a lease is held.
213
+ */
214
+ private publishTimer;
215
+ private publishInFlight;
216
+ /**
217
+ * Why the next debounced publish was scheduled. `"acquired"` (announce on
218
+ * lease acquisition) is gated on this device not yet being in the feed, so a
219
+ * plain reload doesn't republish. `"change"` (account-state delta) always
220
+ * publishes. `"change"` dominates a coalesced burst — a real delta must never
221
+ * be skipped just because an acquisition was also pending.
222
+ */
223
+ private publishReason;
224
+ /**
225
+ * This device's identity, captured ONCE at authentication and reused for
226
+ * every lease operation. Never re-read from `getOrCreateDeviceId()` mid-
227
+ * session, so acquire / refresh / validate always agree on one identity.
228
+ */
229
+ private deviceId;
230
+ /**
231
+ * A session this load restored from storage, rather than one the person
232
+ * connected in it, waits on this before its first write, so a session ended
233
+ * while no page of the site was open cannot write.
234
+ * Unset for a fresh connection. Kept through `clearAuthData`, so a write
235
+ * that was waiting when the check ended the session is told why.
236
+ */
237
+ private restoredSessionCheck;
238
+ constructor(config: ProxyConfig);
239
+ /**
240
+ * Subscribe to shared localStorage changes that can affect the dApp-visible
241
+ * ConnectionInfo (auth state, identity, postage stamps, account type).
242
+ *
243
+ * - `connectedApps` drives auth transitions (new connection / identity switch /
244
+ * disconnect) and triggers `authSuccess` / `disconnectResponse` to the parent.
245
+ * - `identities`, `accounts`, `postageStamps` may change the derived
246
+ * ConnectionInfo without flipping auth state (e.g. rename, default-stamp
247
+ * change, local→synced migration). On change we re-derive ConnectionInfo
248
+ * and emit `connectionInfoChanged` if it actually differs.
249
+ *
250
+ * Note: We always set up these listeners, even when storage might be partitioned.
251
+ * In some browsers/configurations (like localhost development), storage events
252
+ * work between same-origin windows even in iframes. If storage IS partitioned,
253
+ * the listeners simply won't fire, and we fall back to postMessage from the popup.
254
+ */
255
+ private setupStorageListeners;
256
+ /**
257
+ * Queue a reconcile behind whatever reconcile is already running.
258
+ *
259
+ * `refreshStampFromStorage` / `initializeStamper` mutate shared
260
+ * `stamper` / `postageBatchId` state across awaits, so two of them in flight
261
+ * at once emit inconsistent ConnectionInfo. ONE queue for every source: a
262
+ * storage event and an `account-delta` fold are the same work arriving two
263
+ * ways, and a queue each would serialize neither against the other.
264
+ *
265
+ * Rejections are caught and logged here — the chain must survive one failure,
266
+ * and nothing else catches them (the bus dispatch's try/catch only covers a
267
+ * synchronous throw).
268
+ */
269
+ private enqueueReconcile;
270
+ /**
271
+ * Re-read network settings. `beeApiUrl` / `gnosisRpcUrl` are read fresh per
272
+ * call — by the TTL/contract helpers, and by `bee`, which builds the client
273
+ * for a changed URL on its next read — so updating them is all it takes.
274
+ */
275
+ private applyNetworkSettings;
276
+ /**
277
+ * The body of `applyNetworkSettings`, taking the settings as a value: a
278
+ * partitioned session cannot read them from storage and is handed them by
279
+ * the connect popup instead (`hydratePartitionAccount`). One implementation,
280
+ * or the two paths drift — an RPC-only change is invisible to a `beeNodeUrl`
281
+ * guard, and the subsidised-gateway rules below are easy to forget.
282
+ */
283
+ private applyNetworkSettingsValues;
284
+ /**
285
+ * Handle changes to the nested account document. Covers auth transitions
286
+ * (connect / secret change / disconnect) AND derived-ConnectionInfo changes
287
+ * (default-stamp change, new stamp purchased, account rename) — all of which
288
+ * now live in one document.
289
+ *
290
+ * `"storage"`: a `storage` event from another window, or a same-window write
291
+ * the shell made on its own — this device's change, so it publishes.
292
+ * `"bus"`: a same-window write the shell marked `noRepublish` — a peer's
293
+ * delta it folded, a volatile field, a device-local sign-out. The shell
294
+ * sharing this window (the identity UI runs inside the proxy iframe too)
295
+ * makes those beside the proxy, and they reconcile the way a bus delta does,
296
+ * without a publish: republishing a fold stamped a fresh clock on every hop
297
+ * and kept two devices publishing at each other every few seconds (#707).
298
+ */
299
+ private handleAccountStorageChange;
300
+ /**
301
+ * Re-resolve this origin's connection and reconcile the session with it.
302
+ *
303
+ * `source` is where the news came from, and only the disconnect branch cares.
304
+ * A partitioned iframe cannot see connected apps in storage, so a storage
305
+ * event saying "no valid connection" means nothing there — but an
306
+ * `account-delta` from a peer is authoritative, and acting on it is the whole
307
+ * point of that message (docs/Account-Bus.md).
308
+ */
309
+ private reevaluateConnection;
310
+ /**
311
+ * Re-resolve postage stamp and account inputs for the current connection
312
+ * from shared storage. Reinitializes the stamper if the batch, signer
313
+ * key, or account-level inputs (owner / encryption key) changed — the
314
+ * last case handles e.g. local→synced account migration where the
315
+ * postage stamp is unchanged but the underlying account isn't.
316
+ */
317
+ private refreshStampFromStorage;
318
+ /**
319
+ * The only way the resolved stamp changes. The write path — the stamper and
320
+ * the coordinator that writes through it — belongs to the stamp it was built
321
+ * for, so it goes whenever the fields naming that stamp do, before anything
322
+ * is built for the next one. Otherwise the previous coordinator outlives its
323
+ * stamp: after the drive is removed, or the connection moves to another
324
+ * account, an upload still takes that coordinator's lease and spends the old
325
+ * batch while the dApp is told there is no stamp at all.
326
+ */
327
+ private setResolvedStamp;
328
+ /**
329
+ * Authenticate using data from connected apps storage
330
+ */
331
+ private authenticateFromStorage;
332
+ /**
333
+ * Handle messages from the auth popup (same-origin postMessage).
334
+ * Used as storage partitioning fallback when storage events don't fire due to partitioning.
335
+ */
336
+ private handlePopupMessage;
337
+ /**
338
+ * End the connect attempt a refused handover belonged to.
339
+ *
340
+ * The popup cannot be told it was refused — there is no channel back — so it
341
+ * shows "Connected!" while the button here spins on, and the only other
342
+ * thing that ever cleared the flag was the user closing that popup
343
+ * (`checkPopupClosed`), which nothing gave them a reason to do.
344
+ *
345
+ * `isConnecting` first: `showAuthButton` early-returns while it is set, so
346
+ * clearing the flag is what lets the button come back. `authLoading` is
347
+ * already false on every path that reaches here — belt-and-braces, not a
348
+ * second fix.
349
+ *
350
+ * The challenge is deliberately kept. The popup is still open and may yet
351
+ * send a payload this bundle can read; refusing one message ends the
352
+ * attempt's spinner, not the ceremony behind it.
353
+ */
354
+ private endRefusedConnect;
355
+ /**
356
+ * The handed-over chat binding, if it names exactly this parent origin, the
357
+ * address of the chat key of the secret it came with and the account it came
358
+ * with, so the dApp is never shown a statement about another site, key or
359
+ * account. A restored session runs through here again, so a stored binding
360
+ * naming any other address is dropped on reload as well.
361
+ *
362
+ * Local http is allowed in the parse because the comparison with
363
+ * `parentOrigin`, which the browser reported, is the check here. Which sites
364
+ * a binding may name at all is the popup's to decide, and a production popup
365
+ * refuses local http.
366
+ */
367
+ private acceptHandedOverChatBinding;
368
+ /**
369
+ * Write the handed-over session to this partition's own store, sealed so
370
+ * none of it is plain text on disk: it holds the app secret, the derivation
371
+ * key and the stamp's signer key.
372
+ *
373
+ * The wire form, not the parsed one: `AuthDataSchema` revives `BatchId` and
374
+ * `PrivateKey` instances, which do not survive `JSON.stringify`, so what goes
375
+ * in is what the popup sent and what comes back out is parsed the same way it
376
+ * was on arrival.
377
+ *
378
+ * The deadline is the one `hydratePartitionAccount` just computed, read back
379
+ * off the connection rather than recomputed, so the session at rest and the
380
+ * session in memory cannot disagree about when it ends.
381
+ */
382
+ private savePartitionSession;
383
+ /**
384
+ * Re-persist the stored session's account view after a live fold moved it.
385
+ *
386
+ * Without this the record is frozen at the handover: a rotated signer key or
387
+ * a moved default stamp arrives over the bus, updates `partitionAccount`, and
388
+ * then a reload resurrects the pre-fold copy and uploads with it until the
389
+ * next live overlap.
390
+ *
391
+ * Only the account. The deadline stays the one the handover recorded, because
392
+ * `hydratePartitionAccount` recomputes `connectedUntil` on every call — write
393
+ * the in-memory one back and a session extends itself for as long as deltas
394
+ * keep arriving. And the record is edited in the shape it was WRITTEN in
395
+ * (raw JSON), not the parsed one: `AuthDataSchema` revives byte classes that
396
+ * do not survive a second `JSON.stringify`.
397
+ *
398
+ * Never creates a record — a session that failed to persist stays unpersisted.
399
+ */
400
+ private refreshStoredPartitionAccount;
401
+ /** Forget the stored session. Every path that ends one calls this. */
402
+ private clearPartitionSession;
403
+ /**
404
+ * Writes to the stored session wait for sealing, so they run one after
405
+ * another in call order. Otherwise a save that started before a clear could
406
+ * land after it and bring an ended session back. `build` answers the record
407
+ * to write, `null` to remove it, or `undefined` to leave it as it is.
408
+ */
409
+ private writePartitionSession;
410
+ /**
411
+ * The stored record for this parent and its opened wire payload, or
412
+ * `"unavailable"` when this page could not read the wrapping key, so the
413
+ * record may still open on a later load.
414
+ */
415
+ private openStoredPartitionSession;
416
+ /**
417
+ * The stored session for THIS parent, if it is still within its deadline.
418
+ *
419
+ * The key is per dApp origin, because the partition is not: it is scoped to
420
+ * the top-level SITE, so same-site dApps share this store (#671). The
421
+ * `parentOrigin` check below is now the belt to that pair of braces rather
422
+ * than the only thing keeping two dApps apart. An expired, malformed or
423
+ * unopenable record is removed on the way past: it will never become valid
424
+ * again, and a record whose seal does not open is no session. So is a record
425
+ * carrying a chat binding that fails `acceptHandedOverChatBinding`, such as
426
+ * one naming the app secret's address from before sites had a chat key:
427
+ * restored without it, the session would hand out a chat key no binding
428
+ * names, so the person unlocks once and the window signs a fresh one. A record whose
429
+ * wrapping key this page could not read is no session for this page only,
430
+ * and stays stored for a later load to open.
431
+ */
432
+ private readPartitionSession;
433
+ /**
434
+ * Build the in-memory account view for a partitioned session and initialize
435
+ * the write path from it. The vault fields are inert placeholders — the
436
+ * record never touches storage and the seed never leaves first-party
437
+ * context; `SignedInAccount` merely requires their presence.
438
+ */
439
+ private hydratePartitionAccount;
440
+ /**
441
+ * Join the account bus for whatever connection is resolvable right now
442
+ * (idempotent per account). Called from every path that establishes or
443
+ * re-resolves a connection — the unpartitioned ones included, or the bus
444
+ * would never reach past this origin+partition outside Safari.
445
+ */
446
+ private joinAccountBus;
447
+ /**
448
+ * Attach the account's bus transports (docs/Account-Bus.md). Idempotent per
449
+ * account; same code path on every browser — Safari is not special.
450
+ *
451
+ * BOTH transports hang off the account-derived topic, so a context only ever
452
+ * shares a channel with other contexts of the same account. The local one is
453
+ * attached whether or not a signaling URL is configured: without it there is
454
+ * still same-device tab↔tab traffic to carry, and a build with no signaling
455
+ * URL must not lose cross-tab utilization.
456
+ *
457
+ * Because the topic is derived, both transports now attach a few ticks after
458
+ * an auth event rather than at construction, so a peer publishing inside
459
+ * that window loses that one message. Bounded by a single HMAC derivation,
460
+ * and no worse than a tab that has not finished loading — which has no
461
+ * listener either; durable counters reconcile on the next read. `busTopic`
462
+ * is set exactly when the local transport goes live, so it is the signal to
463
+ * wait on.
464
+ *
465
+ * The two attaches are INDEPENDENT. `SignalingTransport` connects in its
466
+ * constructor, where `new URL` / `new WebSocket` throw synchronously on a
467
+ * url that is set but unusable (`ws://` from an https page, a CSP that omits
468
+ * the bus host, a typo) — and that must cost the signaling transport only.
469
+ * Letting it take the local one down produces "no bus at all, for the whole
470
+ * session", silently and indistinguishably from a healthy build with no
471
+ * signaling url at all.
472
+ */
473
+ private ensureAccountBusTransports;
474
+ /**
475
+ * "This device is live", to the account's room. Reads the room and the
476
+ * device id at fire time — the same guard `publishAccountDelta` carries —
477
+ * so a beat scheduled for one account can never name it into another's
478
+ * room during a switch, and one that fires before auth finished says nothing.
479
+ */
480
+ private publishPresence;
481
+ /** Stop beating and forget who was live: the next room starts from nothing. */
482
+ private stopPresence;
483
+ /** Leave the account's bus room: both transports detached and closed, and
484
+ * every latch cleared so the next join is a fresh one. */
485
+ private detachBusTransports;
486
+ /**
487
+ * Clean up resources when the proxy is destroyed.
488
+ * Call this method when the proxy iframe is being unloaded.
489
+ */
490
+ destroy(): void;
491
+ /**
492
+ * Tear the write coordinator down, announcing the partition it held so
493
+ * waiting peers wake now instead of sleeping out their poll interval
494
+ * (docs/Account-Bus.md, bus-accelerated leases). The announcement races the
495
+ * Swarm release it describes, which is harmless: the lock SOCs stay the
496
+ * authority, so a peer woken too early just spends one extra read round.
497
+ */
498
+ private teardownCoordinator;
499
+ private terminateStampWorkerPool;
500
+ private static laneKey;
501
+ /**
502
+ * Hold a lane-scoped delta that arrived with no lane bound to compare it
503
+ * against, merged into whatever that lane already has.
504
+ */
505
+ private bufferLaneUpdate;
506
+ /**
507
+ * Fold the buffered delta for the lane we just bound in, then drop every
508
+ * buffered lane — the ones we did not bind are another device's business.
509
+ * Called on every lease acquire: on the cold path the counters are already
510
+ * seeded from the durable partition-state feed, so this is a harmless
511
+ * monotonic no-op; on the adopt fast path they are not, and this is the
512
+ * whole point.
513
+ */
514
+ private applyPendingLaneUpdate;
515
+ /**
516
+ * Run this holder's answer to a peer's `lease-request`, announcing the
517
+ * partition it gave up so the waiter (and holders further down the rank
518
+ * order) hear about it.
519
+ *
520
+ * The `lease-claim` goes out FIRST. Releasing is two stamped Swarm writes
521
+ * (`yieldIdleLease` → `lease.release()`), which is orders of magnitude
522
+ * longer than a rank step, so announcing only on completion would reach the
523
+ * other holders long after every one of them had begun releasing too — #576
524
+ * with extra steps. A claim is cheap to send and is what the rank step
525
+ * actually budgets for.
526
+ */
527
+ private answerLeaseRequest;
528
+ /**
529
+ * How long this holder waits before answering `requestId`.
530
+ *
531
+ * A waiter needs exactly ONE slot, but the request names no partition, so
532
+ * every idle holder used to release at once: with `partitionCount = 4` all
533
+ * four dropped their lease, each then paid a cold acquire on its next
534
+ * upload, and whoever lost the re-race got "Uploads are unavailable". The
535
+ * waiter re-broadcasts every round, so it repeated.
536
+ *
537
+ * The request id gives every holder the same permutation of the partitions,
538
+ * and each waits its own rank in it. Exactly one draws rank 0 and answers
539
+ * immediately — so the ordinary one-holder handover is not slowed at all —
540
+ * while the rest stand down as soon as they see its `lease-claim`. Only
541
+ * holders that would presently yield take a rank at all (`canYieldForPeer`),
542
+ * so a holder mid-burst does not sit at the front of the order and decline
543
+ * in silence; the next eligible rank answers a step later, which still beats
544
+ * waiting out a poll interval.
545
+ *
546
+ * `scripts/bus-handover-latency.ts` reimplements this election (these
547
+ * handlers are private) to measure the handover against a real cluster.
548
+ * Change the formula here and change it there, or the script starts
549
+ * measuring a race the product does not have.
550
+ */
551
+ private yieldRankDelayMs;
552
+ /** Stop answering `requestId` — somebody else claimed it (or we just did).
553
+ * Remembered as well as cancelled, because the rank timer may already have
554
+ * fired: it hands off to `answerLeaseRequest`, which re-checks this. */
555
+ private standDownFromRequest;
556
+ private markRequestAnswered;
557
+ /** Drop every scheduled answer — nothing they would release is ours now. */
558
+ private cancelPendingYields;
559
+ /**
560
+ * Account-bus subscription: utilization deltas from other contexts, and the
561
+ * lease fast path (docs/Account-Bus.md, bus-accelerated leases). The Swarm
562
+ * lock-SOC protocol stays authoritative — these messages only shortcut its
563
+ * timers.
564
+ */
565
+ private setupBusListeners;
566
+ /**
567
+ * Fold a peer's account snapshot into this session's view and reconcile.
568
+ *
569
+ * This is the only push channel a partitioned iframe has: it cannot see
570
+ * shared storage, so without this a revoke reaches it only when the page
571
+ * closes — and since #547 that session is a full writer holding every stamp's
572
+ * signer key (docs/Account-Bus.md, `account-delta`).
573
+ *
574
+ * Durable truth is unchanged. An unpartitioned session still owns its state
575
+ * through storage; the delta only drives the reconcile, and `clearAuthData`
576
+ * invalidates the stored entry if the outcome is a disconnect.
577
+ */
578
+ private applyAccountDelta;
579
+ /**
580
+ * Create an onProgress callback for upload operations.
581
+ * Returns undefined if progress reporting is disabled.
582
+ */
583
+ private createProgressCallback;
584
+ /**
585
+ * Announce that proxy is ready to receive messages
586
+ * Broadcasts to parent with wildcard origin since we don't know parent origin yet
587
+ */
588
+ private announceReady;
589
+ /**
590
+ * Get the stored postage batch ID
591
+ */
592
+ getPostageBatchId(): string | undefined;
593
+ /**
594
+ * Get the stored signer key
595
+ */
596
+ getSignerKey(): string | undefined;
597
+ /**
598
+ * Initialize the Stamper for client-side signing
599
+ * Uses UtilizationAwareStamper to track bucket usage
600
+ */
601
+ private initializeStamper;
602
+ /**
603
+ * The eager lease claim is a write of its own, so a restored session makes
604
+ * it only once its check allows writes. A session whose check could not
605
+ * complete claims lazily instead, on the first write a later check allows.
606
+ */
607
+ private startLeaseOnceAllowed;
608
+ /**
609
+ * This device's identity, captured once. Lazily initialised here as a
610
+ * fallback; the auth entry points set it eagerly. Reused for every lease
611
+ * operation so acquire / refresh / validate never disagree about who we
612
+ * are (which previously caused false "reclaimed by another device").
613
+ */
614
+ private requireDeviceId;
615
+ private readLeaseCache;
616
+ private writeLeaseCache;
617
+ /**
618
+ * Get or create a StampWorkerPool for parallel signing.
619
+ * Lazy-initialized on first use and reused across uploads, for as long as
620
+ * it signs for the current stamper and has the requested size.
621
+ */
622
+ private getOrCreateWorkerPool;
623
+ /**
624
+ * Save stamper bucket state to IndexedDB, logging a failure rather than
625
+ * throwing. The upload path relies on this: the coordinator flushes in a
626
+ * `finally`, after the upload has already gone out.
627
+ */
628
+ private saveStamperState;
629
+ /**
630
+ * Save stamper bucket state to IndexedDB and tell local peers, throwing when
631
+ * the save fails.
632
+ */
633
+ private persistStamperState;
634
+ /**
635
+ * Execute an upload operation against the right target for the current mode.
636
+ * In subsidised mode (no usable user stamp) the gateway handles stamping, so
637
+ * there is no local stamp state to protect and we run unlocked. In user-stamp
638
+ * mode the write goes through the {@link BatchWriteCoordinator}, which takes
639
+ * the cross-tab write lock, ensures a held partition, and flushes stamper
640
+ * state — the proxy no longer owns any of that.
641
+ */
642
+ private withModeAwareWriteLock;
643
+ /**
644
+ * Save stamper state only in stamper mode.
645
+ * In subsidised mode, there's no local stamp state to persist.
646
+ */
647
+ private saveStamperStateIfNeeded;
648
+ /**
649
+ * Setup message listener for parent and popup messages
650
+ */
651
+ private setupMessageListener;
652
+ /**
653
+ * Handle parent identification
654
+ */
655
+ private handleParentIdentify;
656
+ /**
657
+ * Handle messages from parent window
658
+ */
659
+ private handleParentMessage;
660
+ /**
661
+ * Load authentication data from shared storage (ConnectedApp records).
662
+ */
663
+ private loadAuthData;
664
+ /**
665
+ * Bring a stored session back up, exactly as the popup handover does.
666
+ *
667
+ * Through the same `hydratePartitionAccount`, so there is one function that
668
+ * builds a partitioned session rather than two that drift.
669
+ *
670
+ * The deadline cannot see a revoke made while the tab was closed, so the
671
+ * session comes up for reads at once and checks the account's published
672
+ * state before its first write (`startRestoredSessionCheck`), as a session
673
+ * restored from shared storage does.
674
+ */
675
+ private restorePartitionSession;
676
+ /**
677
+ * Ask the account's published state whether this restored session was ended
678
+ * while no page of the site was open. Ended means what it means
679
+ * everywhere else: the entry is gone, `revokedAt` (Remove), or a
680
+ * `disconnectedAt` newer than the connection this session came from
681
+ * (Disconnect, #667), with the rules in `sync/session-check.ts`.
682
+ *
683
+ * Reads start at once. Writes wait on the answer (`ensureCanWrite`), and an
684
+ * answer that could not be read keeps them refused: an unreachable Swarm
685
+ * says nothing about a revoke, so it neither ends the session nor lets it
686
+ * write. The next write asks again.
687
+ */
688
+ private startRestoredSessionCheck;
689
+ /** Waits for the restored session's check, and refuses unless it allowed. */
690
+ private awaitRestoredSessionAllowed;
691
+ /**
692
+ * The gate every write handler passes. The session check comes first, and
693
+ * the refusal checks run after it because the session can change while it
694
+ * waits.
695
+ */
696
+ private ensureCanWrite;
697
+ /**
698
+ * Look up the postage stamp for the currently connected app's identity
699
+ * by reading from shared localStorage stores.
700
+ */
701
+ private lookupPostageStampForApp;
702
+ /**
703
+ * Look up the account for the currently connected app's identity
704
+ * by reading from shared localStorage stores.
705
+ *
706
+ * @returns Account info with owner address and encryption key, or undefined if not found
707
+ */
708
+ private lookupAccountForApp;
709
+ /**
710
+ * The partition rival set for `accountId`: every device heard live on the
711
+ * account bus, plus the recently signed-in devices of the stored registry
712
+ * (read fresh, so the intent round reflects a device that announced after
713
+ * the coordinator was built).
714
+ *
715
+ * The bus half is the liveness signal — a peer beating in the room is alive
716
+ * by construction, whether or not its roster append ever landed. The
717
+ * registry half is the bootstrap for contexts with no bus (no signaling
718
+ * server configured) and for a device that just signed in and has not
719
+ * beaten yet; it is bounded to `KNOWN_DEVICE_MAX_AGE_MS` because removed
720
+ * (tombstoned) devices won't write, and long-dead ghosts (the device list is
721
+ * append-only) would each add an absent intent read to every acquire — on a
722
+ * flaky gateway that can push a single acquire past its timeout, so a live
723
+ * device can't claim even a FREE partition. A genuinely-live holder this
724
+ * prune drops is still caught by the deviceId-independent occupancy beacon.
725
+ *
726
+ * On any storage error the bus half alone is returned — the lease then falls
727
+ * back to the guard+TTL acquire path against whoever is live.
728
+ */
729
+ private knownDeviceIdsForAccount;
730
+ private lastDeviceRegistryRefreshAt;
731
+ /**
732
+ * Pull the latest account snapshot from the shared feed and union its
733
+ * `metadata.devices` into the locally-stored account, so `knownDeviceIds`
734
+ * reflects a peer that signed in AFTER this device created the account (else
735
+ * the claimer never reads the peer's beacon and they dual-acquire). Throttled
736
+ * (the slot-wait loop re-acquires) and best-effort — on any failure the
737
+ * current registry is used as-is.
738
+ */
739
+ private refreshDeviceRegistryFromSwarm;
740
+ /**
741
+ * Assemble the current account-state snapshot for the connected app's
742
+ * account. Needs no feed signing key, so it stays separate from
743
+ * `buildAccountStateSnapshotForPublish` below — reusing that one would cost
744
+ * two key derivations to send a bus message.
745
+ *
746
+ * `requireDefaultStamp` is the FEED path's precondition, not the snapshot's:
747
+ * that write is paid for by the default stamp, while a bus message costs
748
+ * nothing to send and `metadata.defaultPostageStampBatchID` is optional on
749
+ * the wire. An account with no drives is a supported connected state, and
750
+ * gating the delta on a stamp is how such an account's revokes never reach
751
+ * its partitioned sessions at all.
752
+ */
753
+ private buildAccountStateSnapshot;
754
+ /**
755
+ * Announce this session's account state to the account's other live contexts
756
+ * (docs/Account-Bus.md, `account-delta`). Unlike the feed write below it
757
+ * needs no partition and no lock — it is a message, not a write — so a
758
+ * read-only session still relays what it can see to peers that cannot.
759
+ *
760
+ * `ofEndedConnection` reports a session that has just ENDED (the revoke a
761
+ * storage event revealed), where the entry the snapshot is resolved from is
762
+ * by definition no longer a valid connection.
763
+ */
764
+ private publishAccountDelta;
765
+ /**
766
+ * Assemble the current account-state snapshot for the connected app's account
767
+ * from shared localStorage (the same shape `sync-account` builds from its DI
768
+ * stores). Returns the snapshot plus the feed signing key + owner. Undefined
769
+ * when storage is partitioned or the account/stamp can't be resolved.
770
+ */
771
+ private buildAccountStateSnapshotForPublish;
772
+ /**
773
+ * Schedule a debounced account-state publish. Safe to call from inside the
774
+ * coordinator's lease callbacks: it only arms a timer, so the actual publish
775
+ * runs later, outside any held write lock.
776
+ *
777
+ * A coordinator is NOT a precondition — only the feed half of the publish
778
+ * needs one, and `runAccountStatePublish` checks for it there, after the bus
779
+ * delta has gone out.
780
+ */
781
+ private schedulePublish;
782
+ /**
783
+ * Publish the account snapshot: to the account's live peers over the bus,
784
+ * and to the shared feed via the coordinator (same write lock + held
785
+ * partition). The feed write needs a partition; the bus message does not, so
786
+ * it goes out first and a read-only session still relays to peers that
787
+ * cannot see storage at all. Single-device accounts' feeds are published by
788
+ * the SwarmID UI. Re-arms if a publish is already in flight so the latest
789
+ * state still lands.
790
+ */
791
+ private runAccountStatePublish;
792
+ /**
793
+ * Lift this device's own `removedAt` on a genuine sign-in — #337's rule, at
794
+ * the one seam that can tell a user unlocking their account from a timer.
795
+ *
796
+ * `mergeDevices` used to do this on every refresh, which meant no removal and
797
+ * no expiry ever stuck (#611). Here it happens once, on a fresh `setSecret`
798
+ * handover, and the next publish re-announces us with the tombstone gone —
799
+ * `ensureInRoster` appends when the removed-state differs, so the roster
800
+ * carries the reactivation to peers without any extra write of our own.
801
+ *
802
+ * Clearing `removedAt` is only half of it: `mergeDevicesList` ranks devices
803
+ * on `max(removedAt, lastSignedInAt)`, so a lift that left the old sign-in
804
+ * stamp in place would lose to the very tombstone it is undoing and the next
805
+ * fold would put it straight back. A handover IS a sign-in — the user
806
+ * clicked connect and unlocked in the popup — so it stamps one.
807
+ *
808
+ * Partitioned only: an unpartitioned proxy has no business editing the
809
+ * shared account document behind the identity UI's back. The identity UI has
810
+ * no reactivation seam of its own, and needs none — nothing writes a device
811
+ * tombstone today, and a device that stops beating on the bus is ignored at
812
+ * read rather than tombstoned (#655). If manual removal is ever built, its
813
+ * seam has to do what this one does, both halves included.
814
+ */
815
+ private reactivateThisDevice;
816
+ /**
817
+ * The name this context announces itself under in the device registry.
818
+ *
819
+ * A PARTITIONED proxy keeps its own `swarm-id-device-id` in the partition, so
820
+ * it is a per-dApp device and says which dApp (#570). An UNPARTITIONED one
821
+ * reads the trusted domain's first-party store and therefore shares the
822
+ * device id with the identity UI — it is the same device, and naming it after
823
+ * whichever dApp happened to embed it would be wrong.
824
+ */
825
+ private announcedDeviceName;
826
+ /**
827
+ * Check if a connection is still valid based on connectedUntil timestamp
828
+ */
829
+ private isConnectionValid;
830
+ /**
831
+ * Find the account + connected-app pair for the current parent origin, reading
832
+ * the nested account documents. Resolves ambiguity (the same app connected
833
+ * under multiple accounts) by sorting valid entries by `lastConnectedAt`
834
+ * descending and returning the most recent.
835
+ */
836
+ private findConnectionForParent;
837
+ /**
838
+ * Look up the app secret from shared storage for the current parent origin.
839
+ * Returns the secret if a valid connection is found.
840
+ */
841
+ private lookupAppSecretFromSharedStorage;
842
+ /**
843
+ * Clear authentication data
844
+ */
845
+ private clearAuthData;
846
+ /**
847
+ * Send error message to parent
848
+ */
849
+ /**
850
+ * Answer a request with what went wrong, as a dApp can branch on it (#761):
851
+ * the caught value is classified by `toWireError`; `fallback` is the
852
+ * message for a throw that was not an `Error`.
853
+ */
854
+ private sendErrorToParent;
855
+ private ensureCanUpload;
856
+ /**
857
+ * Whether uploads can be stamped with the account's own postage batch. Both
858
+ * what the dApp is told (`buildConnectionInfo`'s `uploadMode`) and where the
859
+ * bytes go (`isSubsidisedModeActive`) are decided by this one rule.
860
+ */
861
+ private hasUsableUserStamp;
862
+ /**
863
+ * Whether uploads go to the subsidised gateway: one is configured, and there
864
+ * is no usable user stamp to write with instead.
865
+ */
866
+ private isSubsidisedModeActive;
867
+ /**
868
+ * Send message to parent
869
+ */
870
+ private sendToParent;
871
+ /**
872
+ * Send message to the event source (parent window that sent the request)
873
+ */
874
+ private postMessage;
875
+ private handleCheckAuth;
876
+ /**
877
+ * The two public keys the identity carries, memoised on the derivation key
878
+ * they come from: `buildConnectionInfo` runs from eight sites, and the key
879
+ * changes only when the account does. Public halves only, never a secret.
880
+ */
881
+ private identityKeys?;
882
+ private identityKeysFor;
883
+ /**
884
+ * Build the current ConnectionInfo snapshot from in-memory auth state and
885
+ * shared localStorage. Pure — does not send anything.
886
+ */
887
+ private buildConnectionInfo;
888
+ /**
889
+ * Which of the two ways to be upload-less this session hit. Ordered by how
890
+ * early the path gives up, so the answer names the first thing that stopped
891
+ * it rather than the last symptom.
892
+ *
893
+ * Only meaningful once authenticated — an unconnected session has no reason
894
+ * to report beyond not being connected.
895
+ */
896
+ private uploadUnavailableReason;
897
+ /**
898
+ * Recompute ConnectionInfo and send `connectionInfoChanged` to the parent
899
+ * if it actually differs from the last value we sent. Used both on auth
900
+ * transitions and on storage events that affect derived fields.
901
+ */
902
+ private emitConnectionInfoIfChanged;
903
+ private handleIsConnected;
904
+ private handleGetNodeInfo;
905
+ private handleDisconnect;
906
+ /**
907
+ * Show authentication button in the UI
908
+ */
909
+ private showAuthButton;
910
+ private handleConnect;
911
+ /**
912
+ * Open the authentication popup window.
913
+ * Returns true if popup was opened, false if parent origin is not set.
914
+ */
915
+ private openAuthPopup;
916
+ /**
917
+ * Handle login button click
918
+ */
919
+ private handleLoginClick;
920
+ /**
921
+ * Handle disconnect button click
922
+ */
923
+ private handleDisconnectClick;
924
+ /**
925
+ * Set container element for auth button
926
+ */
927
+ setAuthButtonContainer(container: HTMLElement): void;
928
+ private handleUploadData;
929
+ private handleDownloadData;
930
+ private handleUploadFile;
931
+ private handleDownloadFile;
932
+ /** A folder as one manifest (#750); the Swarm-specific part is `uploadCollection`. */
933
+ private handleUploadFiles;
934
+ private handleListFiles;
935
+ private handleUploadChunk;
936
+ private handleDownloadChunk;
937
+ private handleGsocMine;
938
+ private handleGsocSend;
939
+ private handleSocUpload;
940
+ private handleSocRawUpload;
941
+ private handleSocDownload;
942
+ private handleSocRawDownload;
943
+ private handleSocGetOwner;
944
+ /**
945
+ * Derive a stable, app-scoped secret HMAC(appSecret, label) for the connected
946
+ * app. `appSecret` is genuinely secret (unlike the recoverable appKey public
947
+ * key) and never leaves the iframe — only the derived bytes are returned, so
948
+ * the app can seed an unguessable feed topic without exposing metadata (#520).
949
+ */
950
+ private handleDeriveAppSecret;
951
+ /**
952
+ * Hand the authenticated page its site's chat key, the key whose address the
953
+ * site's chat binding names (docs/Chat-Binding.md), so the site's chat can
954
+ * sign with it. Same authentication rule as `handleDeriveAppSecret`, and like
955
+ * it the app secret itself never leaves the frame.
956
+ */
957
+ private handleGetChatKey;
958
+ /**
959
+ * The site names a new Bee node for its session, as the source its viewer
960
+ * picked changes. Needs no sign-in: it says where this site's reads go,
961
+ * which is the site's to decide whether or not anyone is connected.
962
+ *
963
+ * The site naming its node also brings back a subsidised gateway the
964
+ * person's own custom node had switched off (`dropGatewayForOwnCustomNode`).
965
+ */
966
+ private handleSetBeeApiUrl;
967
+ /**
968
+ * Stamp a chunk with the account's own stamp and hand the stamp back, for
969
+ * the app to send through its own Swarm access. The stamp takes the same
970
+ * write path as an upload, so it is returned only after the coordinator has
971
+ * published the partition counter, the guarantee an upload's ack carries.
972
+ * It also needs the stamper state saved, and refuses when that save fails.
973
+ * A restored session stamps only once its session check allows writes, as
974
+ * every write does (`ensureCanWrite`).
975
+ * The account's own lock and counter chunks never
976
+ * come through here, they stay inside the frame and go through its node.
977
+ */
978
+ private handleStampChunk;
979
+ /**
980
+ * Save the counter a stamp spent before the stamp is returned. The write
981
+ * path's own flush only logs a failure, which an upload can afford and a
982
+ * stamp cannot: an account on one device keeps its counter nowhere else, so
983
+ * after a reload the slot would be handed out a second time.
984
+ */
985
+ private persistStamperStateForStamp;
986
+ /**
987
+ * Stamp for this app if its limits allow, and count the stamp. Synchronous
988
+ * from the read of the usage to its write, so two requests can never both
989
+ * take the last stamp an app is allowed. The usage is written before the
990
+ * stamp is returned, so a stamp that could not be counted is never handed
991
+ * out.
992
+ *
993
+ * A single-owner chunk this app had stamped before in this device's lane is
994
+ * stamped again at the same slot with a newer timestamp, which a mutable
995
+ * batch takes as a replacement. That spends no slot, so only the count and
996
+ * the rate apply. A content chunk always takes a new slot.
997
+ *
998
+ * The slot a single-owner chunk went to is not written here. The caller
999
+ * runs `recordSlot` only once the counter that spent it is saved and
1000
+ * published: a record left by a stamp that failed to commit would outlive
1001
+ * the counter, the slot would go to another chunk after a reload, and the
1002
+ * next stamp of this address would replace that chunk on Bee.
1003
+ */
1004
+ private stampWithinAppLimits;
1005
+ /** Stamp at a new slot within the app's limits, and the usage that counts it */
1006
+ private stampNewSlot;
1007
+ /**
1008
+ * The owner addresses of the account's own chunks and keys, for refusing a
1009
+ * single-owner chunk an app asks to have signed as one of them.
1010
+ */
1011
+ private accountInternalOwners;
1012
+ private parseFeedTimestamp;
1013
+ private parseFeedIndex;
1014
+ private makeSequentialFeedIdentifier;
1015
+ private findLatestSequentialIndex;
1016
+ private sequentialNextIndex;
1017
+ private handleFeedGetOwner;
1018
+ private handleEpochFeedDownloadReference;
1019
+ private handleEpochFeedUploadReference;
1020
+ private handleSequentialFeedGetOwner;
1021
+ private resolveSequentialOwner;
1022
+ private parseSequentialPayload;
1023
+ private resolveSequentialIndex;
1024
+ private handleSequentialFeedDownloadPayload;
1025
+ private handleSequentialFeedDownloadRawPayload;
1026
+ private handleSequentialFeedDownloadReference;
1027
+ private buildSequentialPayload;
1028
+ private handleSequentialFeedUploadPayload;
1029
+ private handleSequentialFeedUploadRawPayload;
1030
+ private handleSequentialFeedUploadReference;
1031
+ /**
1032
+ * The account-wide ACT key (#519), or undefined when the session carries no
1033
+ * account to derive it from.
1034
+ */
1035
+ private sharingSecret;
1036
+ /**
1037
+ * The keys this session may read or manage ACT data with: the origin-bound
1038
+ * app key, then the account-wide sharing key. The ACT module picks the one
1039
+ * a share names.
1040
+ */
1041
+ private actKeys;
1042
+ private handleActUploadData;
1043
+ private handleActDownloadData;
1044
+ private handleActAddGrantees;
1045
+ private handleActRevokeGrantees;
1046
+ private handleActGetGrantees;
1047
+ private handleGetPostageBatch;
1048
+ /**
1049
+ * Handle createFeedManifest request
1050
+ * Creates a feed manifest for accessing feed content via URL
1051
+ */
1052
+ private handleCreateFeedManifest;
1053
+ }
1054
+ /**
1055
+ * Optional configuration for the proxy, supplied by the host trusted-domain app.
1056
+ */
1057
+ export interface ProxyConfig {
1058
+ /**
1059
+ * The sites this frame serves (docs/Site-Allow-List.md). A parent whose
1060
+ * origin it refuses gets an `initError` and nothing else.
1061
+ */
1062
+ siteAllowList: SiteAllowList;
1063
+ /**
1064
+ * PostageStamp contract address for on-chain stamp-TTL reads. Defaults to the
1065
+ * Gnosis mainnet deployment; set this (from a build-time env) to the local
1066
+ * bee-compose anvil address when developing against a local chain.
1067
+ */
1068
+ postageStampContractAddress?: string;
1069
+ /**
1070
+ * Account-bus signaling server URL (e.g. `wss://bus.example.com/bus`,
1071
+ * `ws://localhost:5520` in dev). Unset disables the cross-partition/
1072
+ * cross-device bus transport (docs/Account-Bus.md).
1073
+ */
1074
+ signalingUrl?: string;
1075
+ }
1076
+ /**
1077
+ * Initialize the proxy (called from HTML page)
1078
+ */
1079
+ export declare function initProxy(config: ProxyConfig): SwarmIdProxy;