@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.
- package/LICENSE +202 -0
- package/README.md +89 -2
- package/dist/bus/account-bus.d.ts +104 -0
- package/dist/bus/account-delta.d.ts +52 -0
- package/dist/bus/bus-context.d.ts +7 -0
- package/dist/bus/envelope.d.ts +9 -0
- package/dist/bus/messages.d.ts +241 -0
- package/dist/bus/presence.d.ts +62 -0
- package/dist/bus/signaling-transport.d.ts +79 -0
- package/dist/chunk/bmt.d.ts +16 -0
- package/dist/chunk/cac.d.ts +17 -0
- package/dist/chunk/constants.d.ts +10 -0
- package/dist/chunk/encrypted-cac.d.ts +47 -0
- package/dist/chunk/encryption.d.ts +85 -0
- package/dist/chunk/index.d.ts +5 -0
- package/dist/chunks/chat-binding-DO5aGhPl.js +23 -0
- package/dist/chunks/chat-binding-DO5aGhPl.js.map +1 -0
- package/dist/errors.d.ts +35 -0
- package/dist/index.d.ts +27 -0
- package/dist/internal.d.ts +49 -0
- package/dist/internal.esm.js +2 -0
- package/dist/internal.esm.js.map +1 -0
- package/dist/proxy/act/act.d.ts +58 -0
- package/dist/proxy/act/crypto.d.ts +46 -0
- package/dist/proxy/act/grantee-list.d.ts +81 -0
- package/dist/proxy/act/history.d.ts +182 -0
- package/dist/proxy/act/index.d.ts +114 -0
- package/dist/proxy/app-stamp-limits.d.ts +62 -0
- package/dist/proxy/chunk-upload-stream.d.ts +37 -0
- package/dist/proxy/chunking.d.ts +15 -0
- package/dist/proxy/collection.d.ts +38 -0
- package/dist/proxy/download-data.d.ts +27 -0
- package/dist/proxy/errors.d.ts +8 -0
- package/dist/proxy/feed-manifest.d.ts +60 -0
- package/dist/proxy/feeds/epochs/async-finder.d.ts +70 -0
- package/dist/proxy/feeds/epochs/epoch.d.ts +79 -0
- package/dist/proxy/feeds/epochs/finder.d.ts +60 -0
- package/dist/proxy/feeds/epochs/index.d.ts +30 -0
- package/dist/proxy/feeds/epochs/types.d.ts +110 -0
- package/dist/proxy/feeds/epochs/updater.d.ts +76 -0
- package/dist/proxy/feeds/epochs/utils.d.ts +21 -0
- package/dist/proxy/feeds/index.d.ts +4 -0
- package/dist/proxy/feeds/sequence/async-finder.d.ts +14 -0
- package/dist/proxy/feeds/sequence/finder.d.ts +11 -0
- package/dist/proxy/feeds/sequence/index.d.ts +22 -0
- package/dist/proxy/feeds/sequence/types.d.ts +82 -0
- package/dist/proxy/feeds/sequence/updater.d.ts +20 -0
- package/dist/proxy/index.d.ts +5 -0
- package/dist/proxy/manifest-builder.d.ts +164 -0
- package/dist/proxy/mantaray.d.ts +76 -0
- package/dist/proxy/soc-restamp-slots.d.ts +48 -0
- package/dist/proxy/stamp-chunk.d.ts +45 -0
- package/dist/proxy/stamp-worker-handler.d.ts +32 -0
- package/dist/proxy/stamp-worker-pool.d.ts +52 -0
- package/dist/proxy/stamp-worker.d.ts +1 -0
- package/dist/proxy/types.d.ts +38 -0
- package/dist/proxy/upload.d.ts +207 -0
- package/dist/schemas.d.ts +671 -0
- package/dist/stamp-worker.iife.js +1 -0
- package/dist/storage/debounced-uploader.d.ts +61 -0
- package/dist/storage/utilization-store.d.ts +113 -0
- package/dist/swarm-id-client.d.ts +1143 -0
- package/dist/swarm-id-proxy.d.ts +1079 -0
- package/dist/swarm-id.esm.js +2 -0
- package/dist/swarm-id.esm.js.map +1 -0
- package/dist/sync/batch-write-coordinator.d.ts +348 -0
- package/dist/sync/device-roster.d.ts +59 -0
- package/dist/sync/device-state.d.ts +199 -0
- package/dist/sync/fold-account-from-swarm.d.ts +53 -0
- package/dist/sync/index.d.ts +11 -0
- package/dist/sync/merge-snapshot.d.ts +57 -0
- package/dist/sync/partition-intent.d.ts +218 -0
- package/dist/sync/partition-lease.d.ts +531 -0
- package/dist/sync/partition-lock.d.ts +218 -0
- package/dist/sync/partition-state.d.ts +287 -0
- package/dist/sync/session-check.d.ts +29 -0
- package/dist/sync/store-interfaces.d.ts +48 -0
- package/dist/sync/sync-account.d.ts +45 -0
- package/dist/sync/timing-constants.d.ts +32 -0
- package/dist/sync/types.d.ts +18 -0
- package/dist/types.d.ts +3042 -0
- package/dist/utils/account-state-snapshot.d.ts +43 -0
- package/dist/utils/active-devices.d.ts +45 -0
- package/dist/utils/avatar.d.ts +30 -0
- package/dist/utils/batch-utilization.d.ts +840 -0
- package/dist/utils/batch-write-lock.d.ts +12 -0
- package/dist/utils/bee-error.d.ts +11 -0
- package/dist/utils/chat-binding.d.ts +113 -0
- package/dist/utils/coalesced-task.d.ts +28 -0
- package/dist/utils/collection.d.ts +6 -0
- package/dist/utils/connection-info.d.ts +11 -0
- package/dist/utils/constants.d.ts +28 -0
- package/dist/utils/device-id.d.ts +109 -0
- package/dist/utils/hex.d.ts +31 -0
- package/dist/utils/json-rpc.d.ts +34 -0
- package/dist/utils/key-derivation.d.ts +124 -0
- package/dist/utils/lock-soc.d.ts +35 -0
- package/dist/utils/postage-contract.d.ts +143 -0
- package/dist/utils/postage-stamp-association.d.ts +39 -0
- package/dist/utils/promise.d.ts +37 -0
- package/dist/utils/sealed-values.d.ts +23 -0
- package/dist/utils/seed-encryption.d.ts +17 -0
- package/dist/utils/site-allow-list.d.ts +54 -0
- package/dist/utils/stamp-lifespan.d.ts +37 -0
- package/dist/utils/storage-managers.d.ts +62 -0
- package/dist/utils/storage-probe.d.ts +40 -0
- package/dist/utils/tag.d.ts +11 -0
- package/dist/utils/ttl.d.ts +120 -0
- package/dist/utils/url.d.ts +55 -0
- package/dist/utils/versioned-storage.d.ts +183 -0
- package/package.json +91 -3
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge a locally-built account snapshot with the most recent on-Swarm
|
|
3
|
+
* snapshot before publishing.
|
|
4
|
+
*
|
|
5
|
+
* Sync overwrites the feed entry on each write, so a naïve "publish local
|
|
6
|
+
* state" stomps anything a peer just wrote. The fix is to fold the remote
|
|
7
|
+
* snapshot into the local one and publish the union.
|
|
8
|
+
*
|
|
9
|
+
* Strategy per field:
|
|
10
|
+
*
|
|
11
|
+
* - `devices`: last-writer-wins per `deviceId` with a `removedAt` tombstone.
|
|
12
|
+
* The recency clock is `max(removedAt, lastSignedInAt)`, so a removal beats an
|
|
13
|
+
* older sign-in and a newer sign-in re-activates a removed device. The name
|
|
14
|
+
* overlays on its own `nameUpdatedAt` clock, since a rename moves neither.
|
|
15
|
+
* - `connectedApps`: last-writer-wins per `appUrl` (with `revokedAt` tombstone).
|
|
16
|
+
* The chat binding overlays on its own signed date, since a copy handed to a
|
|
17
|
+
* proxy frame carries only that frame's site's binding.
|
|
18
|
+
* - `postageStamps`: last-writer-wins per `batchID` with a `deletedAt`
|
|
19
|
+
* tombstone (recency `max(deletedAt, createdAt)`), so deletions propagate and
|
|
20
|
+
* a fresh re-add (newer `createdAt`) re-activates a deleted stamp.
|
|
21
|
+
* - `metadata.accountName`, `metadata.defaultPostageStampBatchID`,
|
|
22
|
+
* `metadata.partitionCount`: local wins. These are scalar fields set
|
|
23
|
+
* by user actions.
|
|
24
|
+
* - `metadata.createdAt`: keep local's (it's the account's birth date,
|
|
25
|
+
* should be identical anyway).
|
|
26
|
+
* - `timestamp` / `metadata.lastModified`: refreshed to `Date.now()`.
|
|
27
|
+
*
|
|
28
|
+
* The function is pure and deterministic so it's easy to unit-test. The
|
|
29
|
+
* per-collection primitives are exported so the read/refresh path can reuse the
|
|
30
|
+
* exact same rules instead of redefining them.
|
|
31
|
+
*/
|
|
32
|
+
import type { AccountStateSnapshot } from "../utils/account-state-snapshot";
|
|
33
|
+
import type { Device, ConnectedApp, PostageStamp } from "../schemas";
|
|
34
|
+
export declare function mergeSnapshotWithRemote(local: AccountStateSnapshot, remote: AccountStateSnapshot | undefined): AccountStateSnapshot;
|
|
35
|
+
export declare function mergeDevicesList(local: Device[], remote: Device[]): Device[];
|
|
36
|
+
/**
|
|
37
|
+
* @param accountId - the account whose connected apps these are, the only
|
|
38
|
+
* signer whose chat binding a merge ranks by date over another
|
|
39
|
+
*/
|
|
40
|
+
export declare function mergeConnectedApps(local: ConnectedApp[], remote: ConnectedApp[], accountId: string): ConnectedApp[];
|
|
41
|
+
export declare function mergePostageStamps(local: PostageStamp[], remote: PostageStamp[]): PostageStamp[];
|
|
42
|
+
/**
|
|
43
|
+
* True when `latest` already includes every device / connected-app /
|
|
44
|
+
* postage-stamp present in `mine` (compared by their natural keys — the same
|
|
45
|
+
* keys `mergeSnapshotWithRemote` unions on; timestamps and scalar metadata are
|
|
46
|
+
* ignored).
|
|
47
|
+
*
|
|
48
|
+
* Used by the publish path to tell a *real* last-writer-wins loss (our entities
|
|
49
|
+
* were dropped) apart from a harmless co-writer that published the same account
|
|
50
|
+
* (e.g. the proxy announcing this device while the UI also syncs it) — whose
|
|
51
|
+
* union still contains us, so convergence held and there is nothing to retry.
|
|
52
|
+
*
|
|
53
|
+
* Note: this is membership-only. Tombstone/scalar nuances (a revoke or an
|
|
54
|
+
* account rename stomped by a co-writer) are NOT detected here; the union
|
|
55
|
+
* merge's recency rules reconcile those on the next sync.
|
|
56
|
+
*/
|
|
57
|
+
export declare function snapshotContainsContribution(mine: AccountStateSnapshot, latest: AccountStateSnapshot): boolean;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-device partition-INTENT SOCs — Phase 2 of the partition-lock hardening
|
|
3
|
+
* (see docs/Partition-Lock-Hardening-Plan.md, "Extension that covers the
|
|
4
|
+
* symmetric case: per-device intent SOCs").
|
|
5
|
+
*
|
|
6
|
+
* The lock SOC lives at a single static address. Across disjoint gateways a
|
|
7
|
+
* node serves that address from a frozen cache (no TTL, no invalidation), so
|
|
8
|
+
* contenders for a *free* partition never see each other and all bind it —
|
|
9
|
+
* the disjoint-gateway dual-acquire bug. Tweaking the guard/TTL timeouts can't
|
|
10
|
+
* help: the failure is non-visibility, not propagation latency.
|
|
11
|
+
*
|
|
12
|
+
* Intent SOCs convert "mutable-SOC cache coherence" (which Swarm doesn't
|
|
13
|
+
* guarantee) into "push-sync receipt + retrieval routing" (which it does):
|
|
14
|
+
*
|
|
15
|
+
* identifier = keccak256("swarm-id-partition-intent-v1:" || partition
|
|
16
|
+
* || ":" || deviceId || ":" || epochBucket)
|
|
17
|
+
* owner = backup signer (shared across the account's devices)
|
|
18
|
+
* encryption = swarmEncryptionKey
|
|
19
|
+
*
|
|
20
|
+
* Each contender writes ONLY its own intent address and reads every other
|
|
21
|
+
* known device's intent address. A read of an address your node has never
|
|
22
|
+
* written (and, because the address rotates per epoch, never retrieved
|
|
23
|
+
* before) cannot be short-circuited from the local store — it forces a
|
|
24
|
+
* network retrieval to the address's storage neighborhood, where the rival's
|
|
25
|
+
* receipt-backed push-sync placed its replicas. So contenders see each other,
|
|
26
|
+
* order themselves by `generation`, and only the unique global-minimum binds
|
|
27
|
+
* the lock.
|
|
28
|
+
*
|
|
29
|
+
* Irreducible limit (documented): absence is unprovable on Swarm — a retrieval
|
|
30
|
+
* timeout can't distinguish "no rival intent" from "the network failed to find
|
|
31
|
+
* it". We treat a timed-out read as "no intent" to keep liveness (a single
|
|
32
|
+
* flaky device must not deadlock), so the guarantee is "when the network
|
|
33
|
+
* works, rivals are seen"; genuine network partition still falls back to the
|
|
34
|
+
* existing guard + TTL + refresh backstop.
|
|
35
|
+
*
|
|
36
|
+
* Slot safety: an intent is stamped into the CONTENDED partition's reserved
|
|
37
|
+
* slot (= the partition index, `< DATA_COUNTER_START`), via
|
|
38
|
+
* `UtilizationAwareStamper.reserveIntentSocSlot`. It therefore can NEVER share
|
|
39
|
+
* a postage `(bucket, slot)` with user data (data lives at
|
|
40
|
+
* `>= DATA_COUNTER_START`) — a deterministic guarantee, not probabilistic.
|
|
41
|
+
*
|
|
42
|
+
* Two residuals remain (both ~1/65536 per contending pair per round, far rarer
|
|
43
|
+
* than the systematic disjoint-gateway failure, and NOT closed here):
|
|
44
|
+
* - Two contenders for the same partition whose per-epoch intent addresses
|
|
45
|
+
* hash into the same bucket both route to that partition's reserved slot;
|
|
46
|
+
* the older loses its stamp and reads as "no intent", so on disjoint
|
|
47
|
+
* gateways both may "win" → a rare dual-acquire. (A verify-own-intent
|
|
48
|
+
* back-off or per-device slot would close it.)
|
|
49
|
+
* - An intent may overstamp the contended partition's own (stale) lock SOC
|
|
50
|
+
* (harmless — re-acquired) or a published state chunk (→ `readFailed` →
|
|
51
|
+
* read-only fallback). Liveness-only, never data loss.
|
|
52
|
+
*/
|
|
53
|
+
import { Bee, Identifier, PrivateKey, type BatchId, type EthAddress, type Stamper } from "@ethersphere/bee-js";
|
|
54
|
+
import { INTENT_EPOCH_MS } from "./timing-constants";
|
|
55
|
+
import { type PartitionIntentPayload } from "../schemas";
|
|
56
|
+
import { type PartitionLockGeneration } from "./partition-lock";
|
|
57
|
+
export type { PartitionIntentPayload };
|
|
58
|
+
export { INTENT_EPOCH_MS };
|
|
59
|
+
export declare const INTENT_READ_TIMEOUT_MS = 2500;
|
|
60
|
+
/**
|
|
61
|
+
* Total window an intent round polls rivals before binding a fresh claim.
|
|
62
|
+
* Sized to the gateway's write→cross-device-retrieve propagation delay: a peer
|
|
63
|
+
* that wrote its intent/beacon seconds ago isn't immediately readable, so a
|
|
64
|
+
* single read races ahead of propagation and misses it. Polling over this
|
|
65
|
+
* window lets the peer surface. Tunable per gateway (lease/coordinator opts +
|
|
66
|
+
* the `swarm-id-partition-tuning` localStorage override).
|
|
67
|
+
*/
|
|
68
|
+
export declare const INTENT_GUARD_WINDOW_MS = 12000;
|
|
69
|
+
/** Interval between rival re-reads within the guard window. */
|
|
70
|
+
export declare const INTENT_GUARD_POLL_MS = 2500;
|
|
71
|
+
/**
|
|
72
|
+
* Grace applied to a found beacon's `leasedUntil` when deciding liveness. A
|
|
73
|
+
* beacon is only ever read at the current/previous epoch bucket, so a found one
|
|
74
|
+
* was written ≤ ~2 epochs ago — bounded-fresh by its rotating address. Its
|
|
75
|
+
* `leasedUntil` (writeTime + lock TTL ≈ 30s) can still lapse before the holder's
|
|
76
|
+
* NEXT beacon becomes cross-device retrievable, so a live holder whose freshest
|
|
77
|
+
* beacon hasn't propagated would be misread as departed. Treating a beacon as
|
|
78
|
+
* live while `leasedUntil > now - GRACE` bridges that propagation gap; the
|
|
79
|
+
* bucket-bounded read window means this can never resurrect an aged-out beacon.
|
|
80
|
+
*/
|
|
81
|
+
export declare const INTENT_LIVENESS_GRACE_MS: number;
|
|
82
|
+
/** `floor(nowMs / INTENT_EPOCH_MS)` — the current intent epoch bucket. */
|
|
83
|
+
export declare function intentEpochBucket(nowMs: number): number;
|
|
84
|
+
/**
|
|
85
|
+
* Build the per-(partition, device, epoch) intent-SOC identifier. The address
|
|
86
|
+
* rotates with `epochBucket`, so it is fresh per contention round — neither
|
|
87
|
+
* the writer's nor a reader's node has a cached copy.
|
|
88
|
+
*/
|
|
89
|
+
export declare function makePartitionIntentIdentifier(batchId: BatchId, partition: number, deviceId: string, epochBucket: number): Identifier;
|
|
90
|
+
/**
|
|
91
|
+
* 32-byte SOC chunk address for an intent — `keccak256(identifier ‖ owner)`,
|
|
92
|
+
* the same derivation `uploadSOC` uses. Computable before the upload so the
|
|
93
|
+
* stamper can reserve the chunk's slot (route it to the contended partition's
|
|
94
|
+
* reserved index instead of a data lane).
|
|
95
|
+
*/
|
|
96
|
+
export declare function intentSocAddress(batchId: BatchId, partition: number, deviceId: string, epochBucket: number, owner: EthAddress): Uint8Array;
|
|
97
|
+
/** Build the deviceId-INDEPENDENT occupancy identifier for (batch, partition,
|
|
98
|
+
* epoch). Batch-scoped for the same reason the lock is (#589): a beacon on
|
|
99
|
+
* lane p of batch X says nothing about lane p of batch Y. */
|
|
100
|
+
export declare function makePartitionOccupancyIdentifier(batchId: BatchId, partition: number, epochBucket: number): Identifier;
|
|
101
|
+
/** 32-byte SOC address for an occupancy beacon (for stamper slot reservation). */
|
|
102
|
+
export declare function partitionOccupancyAddress(batchId: BatchId, partition: number, epochBucket: number, owner: EthAddress): Uint8Array;
|
|
103
|
+
/**
|
|
104
|
+
* Write this device's intent for (partition, epochBucket). The payload carries
|
|
105
|
+
* the generation the device intends to claim with, so rivals can order against
|
|
106
|
+
* it. Uses the shared backup signer as owner (same as the lock SOC); each
|
|
107
|
+
* device only ever writes its own identifier.
|
|
108
|
+
*/
|
|
109
|
+
export declare function writePartitionIntent(opts: {
|
|
110
|
+
bee: Bee;
|
|
111
|
+
stamper: Stamper;
|
|
112
|
+
backupSigner: PrivateKey;
|
|
113
|
+
swarmEncryptionKey: Uint8Array;
|
|
114
|
+
batchId: BatchId;
|
|
115
|
+
partition: number;
|
|
116
|
+
deviceId: string;
|
|
117
|
+
epochBucket: number;
|
|
118
|
+
generation: PartitionLockGeneration;
|
|
119
|
+
/**
|
|
120
|
+
* Present when this write is a holder PRESENCE BEACON (re-published each
|
|
121
|
+
* refresh): lets a reading joiner apply a `leasedUntil > now` liveness test.
|
|
122
|
+
* Omitted for a pre-claim intent (the symmetric-race announce).
|
|
123
|
+
*/
|
|
124
|
+
leasedUntil?: number;
|
|
125
|
+
}): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Publish this device's OCCUPANCY beacon for (partition, epochBucket) — same
|
|
128
|
+
* payload as a presence beacon but at the deviceId-independent occupancy
|
|
129
|
+
* address, so a contender that doesn't know this device can still detect it
|
|
130
|
+
* holds the partition. Always carries `leasedUntil` (it only ever announces a
|
|
131
|
+
* live hold).
|
|
132
|
+
*/
|
|
133
|
+
export declare function writePartitionOccupancy(opts: {
|
|
134
|
+
bee: Bee;
|
|
135
|
+
stamper: Stamper;
|
|
136
|
+
backupSigner: PrivateKey;
|
|
137
|
+
swarmEncryptionKey: Uint8Array;
|
|
138
|
+
batchId: BatchId;
|
|
139
|
+
partition: number;
|
|
140
|
+
deviceId: string;
|
|
141
|
+
epochBucket: number;
|
|
142
|
+
generation: PartitionLockGeneration;
|
|
143
|
+
leasedUntil: number;
|
|
144
|
+
}): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* Read a single rival's intent for (partition, epochBucket). Returns `undefined`
|
|
147
|
+
* when missing / timed out / malformed (treated as "no intent" — see header).
|
|
148
|
+
*/
|
|
149
|
+
export declare function readPartitionIntent(opts: {
|
|
150
|
+
bee: Bee;
|
|
151
|
+
backupSigner: PrivateKey;
|
|
152
|
+
swarmEncryptionKey: Uint8Array;
|
|
153
|
+
batchId: BatchId;
|
|
154
|
+
partition: number;
|
|
155
|
+
deviceId: string;
|
|
156
|
+
epochBucket: number;
|
|
157
|
+
timeoutMs?: number;
|
|
158
|
+
/** See `readPartitionSoc`. The polling round passes false. */
|
|
159
|
+
retryOn5xx?: boolean;
|
|
160
|
+
}): Promise<PartitionIntentPayload | undefined>;
|
|
161
|
+
/**
|
|
162
|
+
* Read the deviceId-INDEPENDENT occupancy beacon for (partition, epochBucket).
|
|
163
|
+
* Lets a contender detect a live holder it doesn't know about.
|
|
164
|
+
*/
|
|
165
|
+
export declare function readPartitionOccupancy(opts: {
|
|
166
|
+
bee: Bee;
|
|
167
|
+
backupSigner: PrivateKey;
|
|
168
|
+
swarmEncryptionKey: Uint8Array;
|
|
169
|
+
batchId: BatchId;
|
|
170
|
+
partition: number;
|
|
171
|
+
epochBucket: number;
|
|
172
|
+
timeoutMs?: number;
|
|
173
|
+
}): Promise<PartitionIntentPayload | undefined>;
|
|
174
|
+
/**
|
|
175
|
+
* Run an intent round for a fresh claim of `partition`: announce our intent,
|
|
176
|
+
* then read every other known device's intent for the current AND previous
|
|
177
|
+
* epoch bucket (covering the rotation boundary). Returns whether this device
|
|
178
|
+
* is the round's winner.
|
|
179
|
+
*
|
|
180
|
+
* Winner = the strictly-minimum generation (earliest `timestampMs`, then
|
|
181
|
+
* smallest `tiebreaker`). We lose iff any rival's intent orders below ours.
|
|
182
|
+
* `compareGenerations` is a total order and distinct devices never tie
|
|
183
|
+
* (tiebreaker derives from `keccak256(deviceId)`), so exactly one contender
|
|
184
|
+
* wins. With no known rivals we win by default (a brand-new device not yet in
|
|
185
|
+
* the registry falls back to the existing guard + TTL behaviour).
|
|
186
|
+
*
|
|
187
|
+
* @returns `"win"` to proceed with the claim, `"lose"` to back off (read-only).
|
|
188
|
+
*/
|
|
189
|
+
export declare function resolveIntentRound(opts: {
|
|
190
|
+
bee: Bee;
|
|
191
|
+
stamper: Stamper;
|
|
192
|
+
backupSigner: PrivateKey;
|
|
193
|
+
swarmEncryptionKey: Uint8Array;
|
|
194
|
+
batchId: BatchId;
|
|
195
|
+
partition: number;
|
|
196
|
+
deviceId: string;
|
|
197
|
+
generation: PartitionLockGeneration;
|
|
198
|
+
knownDeviceIds: string[];
|
|
199
|
+
now: number;
|
|
200
|
+
timeoutMs?: number;
|
|
201
|
+
/**
|
|
202
|
+
* Poll rivals over this window before deciding (default 0 = a single read,
|
|
203
|
+
* used by tests). Sized to the gateway propagation delay so a peer's recent
|
|
204
|
+
* intent/beacon surfaces before we bind. See `INTENT_GUARD_WINDOW_MS`.
|
|
205
|
+
*/
|
|
206
|
+
guardWindowMs?: number;
|
|
207
|
+
/** Interval between polls within the guard window. */
|
|
208
|
+
guardPollMs?: number;
|
|
209
|
+
/**
|
|
210
|
+
* Release WATERMARK for this partition, when the caller observed it freed by
|
|
211
|
+
* an explicit release sentinel. A rival's live presence beacon at or below
|
|
212
|
+
* this generation is the just-released holder's lingering GHOST (still within
|
|
213
|
+
* its lease TTL at a live per-epoch address, but no longer a claim), so it
|
|
214
|
+
* must NOT lose us the round. A genuine post-release claimant has a strictly
|
|
215
|
+
* newer generation and still beats us. Omitted → every live beacon counts.
|
|
216
|
+
*/
|
|
217
|
+
releasedGeneration?: PartitionLockGeneration;
|
|
218
|
+
}): Promise<"win" | "lose">;
|