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