@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,143 @@
1
+ /**
2
+ * PostageStamp contract address on Gnosis Chain. Lowercased — RPC nodes accept
3
+ * a non-checksummed `to`, and lowercasing sidesteps any checksum mistake.
4
+ */
5
+ export declare const POSTAGE_STAMP_CONTRACT_ADDRESS = "0x45a1502382541cd610cc9068e88727426b696293";
6
+ /**
7
+ * Picks the PostageStamp contract address that matches the chain `rpcUrl` points
8
+ * at. A dev-override address (bee-compose anvil) is only honoured against a local
9
+ * RPC; against any remote RPC (Gnosis mainnet) it would read a nonexistent
10
+ * contract — `eth_call` returns empty, the batch looks unknown, and callers
11
+ * silently fall back to a bogus price estimate. Tying the address to the RPC
12
+ * network stops the two from drifting apart, which is what produced wildly wrong
13
+ * estimated expiry dates when a dev build read a mainnet batch (#344).
14
+ */
15
+ export declare function resolvePostageStampContractAddress(rpcUrl: string, localContractAddress?: string): string;
16
+ /**
17
+ * Decoded `batches(bytes32)` tuple. Field names mirror the contract's `Batch`
18
+ * struct. `normalisedBalance` is a per-chunk value denominated in PLUR; it is
19
+ * the cumulative outpayment level at which this batch runs out.
20
+ */
21
+ export interface OnChainPostageBatch {
22
+ owner: string;
23
+ depth: number;
24
+ bucketDepth: number;
25
+ immutableFlag: boolean;
26
+ normalisedBalance: bigint;
27
+ lastUpdatedBlockNumber: bigint;
28
+ }
29
+ /**
30
+ * A consistent snapshot of one batch plus the global accounting needed to turn
31
+ * its `normalisedBalance` into a remaining TTL.
32
+ */
33
+ export interface OnChainBatchState {
34
+ batch: OnChainPostageBatch;
35
+ /** Per-chunk cumulative outpayment so far, in PLUR (`currentTotalOutPayment()`). */
36
+ currentTotalOutPayment: bigint;
37
+ /** Per-chunk per-block storage price, in PLUR (`lastPrice()`). */
38
+ lastPrice: bigint;
39
+ }
40
+ /**
41
+ * Decodes the ABI-encoded return of `batches(bytes32)` — a static tuple of
42
+ * `(address, uint8, uint8, bool, uint256, uint256)`, i.e. six 32-byte words.
43
+ * @throws if the payload is too short to hold the tuple.
44
+ */
45
+ export declare function decodeBatches(hex: string): OnChainPostageBatch;
46
+ /** Decodes a single-`uint256` return payload to a BigInt. */
47
+ export declare function decodeUint(hex: string): bigint;
48
+ /**
49
+ * Fetches a consistent on-chain snapshot of a postage batch from the
50
+ * PostageStamp contract: its `batches(batchId)` tuple plus the global
51
+ * `currentTotalOutPayment()` and `lastPrice()`.
52
+ *
53
+ * @param rpcUrl - Gnosis Chain JSON-RPC URL
54
+ * @param batchId - 32-byte hex batch ID, with or without `0x` prefix
55
+ * @param contractAddress - PostageStamp contract address to read from. Defaults
56
+ * to the Gnosis mainnet deployment; override for a local dev chain
57
+ * (bee-compose anvil deploys it at a different address).
58
+ * @returns The decoded state, or `undefined` if the batch is unknown to the
59
+ * contract (zero owner) or the RPC request fails. Never throws — the
60
+ * UI falls back to other expiry sources on `undefined`.
61
+ */
62
+ /**
63
+ * Outcome of an on-chain batch read, keeping the two failure modes distinct:
64
+ * - `found` — the contract knows the batch (non-zero owner).
65
+ * - `not-found` — the contract returned an all-zero tuple; the batch
66
+ * authoritatively does not exist on this chain.
67
+ * - `error` — the RPC request failed or returned an undecodable payload, so
68
+ * existence is *unknown* (not the same as "does not exist").
69
+ */
70
+ export type OnChainBatchResult = {
71
+ status: "found";
72
+ state: OnChainBatchState;
73
+ } | {
74
+ status: "not-found";
75
+ } | {
76
+ status: "error";
77
+ };
78
+ /**
79
+ * Reads a batch's on-chain state, distinguishing "definitively absent" from
80
+ * "couldn't check". {@link fetchOnChainBatchState} is the simpler wrapper that
81
+ * collapses both into `undefined`.
82
+ */
83
+ export declare function fetchOnChainBatchStateResult(rpcUrl: string, batchId: string, contractAddress?: string): Promise<OnChainBatchResult>;
84
+ export declare function fetchOnChainBatchState(rpcUrl: string, batchId: string, contractAddress?: string): Promise<OnChainBatchState | undefined>;
85
+ /**
86
+ * Computes a batch's remaining TTL in seconds from an on-chain snapshot, using
87
+ * the same integer math as the storage-incentives contract and Bee node.
88
+ *
89
+ * @returns Remaining seconds (`0` when expired), or `undefined` when the price
90
+ * is zero — the batch then drains at no cost and has no finite expiry,
91
+ * which we cannot render as a date. On mainnet the PriceOracle floor
92
+ * keeps `lastPrice` well above zero, so this only guards dev chains.
93
+ */
94
+ export declare function calculateContractTTLSeconds(state: OnChainBatchState): number | undefined;
95
+ /**
96
+ * Convenience wrapper: fetches a batch's on-chain state and returns its
97
+ * remaining TTL in seconds. This is the contract-backed counterpart to
98
+ * {@link fetchBatchTTL} (which reads the Bee node), and unlike it works for any
99
+ * batch the contract knows about, regardless of whether the configured Bee node
100
+ * tracks it.
101
+ *
102
+ * @param contractAddress - PostageStamp contract address (defaults to mainnet;
103
+ * override for a local dev chain).
104
+ * @returns Remaining TTL in seconds (`0` when expired), or `undefined` when the
105
+ * batch is unknown, the RPC request fails, or the price is zero.
106
+ */
107
+ export declare function fetchBatchTTLFromContract(rpcUrl: string, batchId: string, contractAddress?: string): Promise<number | undefined>;
108
+ /**
109
+ * Resolves a batch's remaining TTL (seconds) from the most authoritative source
110
+ * available, in order:
111
+ * 1. The PostageStamp contract, read directly by batchId — ground truth that
112
+ * works for any batch, even one the configured Bee node has never seen.
113
+ * 2. The Bee node's `batchTTL` — also live chain state, but only for batches
114
+ * the node tracks.
115
+ *
116
+ * This is the single canonical "best remaining TTL" lookup; callers layer a
117
+ * price-based approximation ({@link calculateTTLSeconds}) on top when both
118
+ * sources return `undefined`.
119
+ *
120
+ * @param gnosisRpcUrl - Gnosis Chain JSON-RPC URL (for the contract read)
121
+ * @param beeUrl - Bee node URL (fallback)
122
+ * @param batchId - 32-byte hex batch ID, with or without `0x` prefix
123
+ * @param localContractAddress - PostageStamp address for a local dev chain. Only
124
+ * honoured when `gnosisRpcUrl` targets a local node; against any remote
125
+ * RPC the Gnosis mainnet deployment is used regardless (see
126
+ * {@link resolvePostageStampContractAddress}).
127
+ * @returns Remaining TTL in seconds, or `undefined` if neither source can answer.
128
+ */
129
+ export declare function fetchAuthoritativeBatchTTL(gnosisRpcUrl: string, beeUrl: string, batchId: string, localContractAddress?: string): Promise<number | undefined>;
130
+ /**
131
+ * Resolves a batch's existence and remaining TTL, treating the on-chain contract
132
+ * as the source of truth. A contract `not-found` is authoritative — a Bee node
133
+ * that happens to track the batch cannot override the chain. The Bee node is
134
+ * consulted only when the contract read itself failed (RPC unreachable), as a
135
+ * best-effort second opinion.
136
+ *
137
+ * Unlike {@link fetchAuthoritativeBatchTTL} (best-effort TTL, falls back to Bee
138
+ * even on contract `not-found`), this is the stricter lookup for existence-aware
139
+ * UI.
140
+ *
141
+ * @param localContractAddress - PostageStamp address for a local dev chain; only
142
+ * honoured against a local RPC (see {@link resolvePostageStampContractAddress}).
143
+ */
@@ -0,0 +1,39 @@
1
+ import type { ConnectedApp, PostageStamp, SignedInAccount } from "../schemas";
2
+ /**
3
+ * Resolve which postage stamp an app should upload with.
4
+ *
5
+ * An app may carry its own batch override (`postageStampBatchID`); otherwise it
6
+ * falls back to the account's default stamp. The account owns the stamp set, so
7
+ * these pointers are the single source of truth.
8
+ *
9
+ * The lookup is existence-checked: a pointer whose stamp is missing (e.g. a
10
+ * removed or replaced batch) is skipped so resolution falls through to the next
11
+ * candidate instead of failing.
12
+ *
13
+ * Paired with `stampsReachableByApp` below, which decides what a partitioned
14
+ * session may HOLD while this decides what it SPENDS — over the same two
15
+ * pointers, and deliberately differing on tombstones: this one skips them (a
16
+ * deleted stamp cannot be spent), that one keeps them (a session learns its
17
+ * stamp is deleted no other way). Change the pointer rule in one and the other
18
+ * has to follow, or a session holds a stamp it cannot resolve, or resolves one
19
+ * it was never handed.
20
+ */
21
+ export declare function resolveStampForApp(app: Pick<ConnectedApp, "postageStampBatchID">, account: Pick<SignedInAccount, "defaultPostageStampBatchID">, stamps: PostageStamp[]): PostageStamp | undefined;
22
+ /**
23
+ * The stamps a connected app's session can ever reach: the ones its pointers
24
+ * name — its own batch override, and the account default it falls through to.
25
+ *
26
+ * This is what a PARTITIONED session is handed and allowed to keep (#578). It
27
+ * holds its account view in memory, in a context embedded by an arbitrary dApp
28
+ * page, and it can only ever spend the stamp `resolveStampForApp` picks — so
29
+ * the rest of the collection is signer keys it has no use for. Least privilege
30
+ * rather than a broken boundary: an unpartitioned proxy reads the same material
31
+ * out of shared storage, but it does not have to be handed it.
32
+ *
33
+ * BOTH pointers, not just the winner: the default is the fallthrough
34
+ * `resolveStampForApp` takes when the override's stamp is gone, so shipping
35
+ * only the override would turn a recoverable stale pointer into a session that
36
+ * cannot upload at all. Tombstones its pointers still name are kept too — a
37
+ * tombstone is how the session learns the stamp it was spending is deleted.
38
+ */
39
+ export declare function stampsReachableByApp(app: Pick<ConnectedApp, "postageStampBatchID">, account: Pick<SignedInAccount, "defaultPostageStampBatchID">, stamps: PostageStamp[]): PostageStamp[];
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Rejection type for {@link withTimeout}. Callers classify a timed-out read
3
+ * (INCONCLUSIVE — the target may exist behind a slow gateway) apart from a
4
+ * clean miss / other failure with `error instanceof TimeoutError` — never by
5
+ * matching the message text, which is display-only.
6
+ */
7
+ export declare class TimeoutError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ /**
11
+ * Time-bound `work`: resolve/reject with `work` if it settles within `ms`, else
12
+ * reject with a {@link TimeoutError}. Unlike a hand-rolled
13
+ * `Promise.race([work, rejectionTimer])`, the timer is cleared once the race
14
+ * settles, so a fast read leaves no stray timer to fire later (matters in
15
+ * tight read loops).
16
+ */
17
+ export declare function withTimeout<T>(work: Promise<T>, ms: number, message: string): Promise<T>;
18
+ /**
19
+ * Resolve after `ms` milliseconds — the default delay behind a poll or backoff.
20
+ *
21
+ * A caller whose timing a test needs to drive should keep taking an injectable
22
+ * wait and pass this as its default (as `acquirePartitionLock` does with
23
+ * `opts.wait`) rather than calling it directly, which would pin real time into
24
+ * the test path.
25
+ */
26
+ export declare function sleep(ms: number): Promise<void>;
27
+ /**
28
+ * Like {@link withTimeout}, but the deadline is `ms` from the last
29
+ * `keepAlive()` the work reported (or from the start, if it reported nothing) —
30
+ * so it bounds silence, not total elapsed time. For work of unbounded duration
31
+ * whose progress is observable: a payment signed in a wallet, a long upload.
32
+ *
33
+ * `work` is a function so it can be handed the `keepAlive` callback. A
34
+ * synchronous throw from it becomes a rejection, and a `keepAlive` after the
35
+ * work settles is ignored — both so the timer is always cleared.
36
+ */
37
+ export declare function withIdleTimeout<T>(work: (keepAlive: () => void) => Promise<T>, ms: number, message: string): Promise<T>;
@@ -0,0 +1,23 @@
1
+ /** Marks a stored string as sealed, and names the format. */
2
+ export declare const SEALED_VALUE_PREFIX = "sealed:v1:";
3
+ /**
4
+ * Whether this page seals with a key of its own in place of the browser's
5
+ * IndexedDB. What it seals now no later load can open.
6
+ */
7
+ export declare function sealsWithPageKey(): Promise<boolean>;
8
+ export declare function isSealedValue(value: unknown): value is string;
9
+ /**
10
+ * Seal a value for storage. One value seals to one sealed form for the life of
11
+ * the page, so rewriting an unchanged record writes the same bytes.
12
+ */
13
+ export declare function sealValue(plaintext: string): Promise<string>;
14
+ /**
15
+ * Whether this page failed to reach the wrapping key for this value, as
16
+ * opposed to reaching it and finding the value will not open. Stays true for
17
+ * the rest of the page even if a later try opens it.
18
+ */
19
+ export declare function isSealedValueUnavailable(sealed: string): boolean;
20
+ /** Open these sealed values into memory, so `openedValue` can read them. */
21
+ export declare function primeSealedValues(sealed: Iterable<string>): Promise<void>;
22
+ /** The plain value, if this page has opened it. */
23
+ export declare function openedValue(sealed: string): string | undefined;
@@ -0,0 +1,17 @@
1
+ export declare function randomSalt(): Uint8Array;
2
+ /** Encrypt bytes; returns hex of IV || ciphertext. */
3
+ export declare function encryptSeed(data: Uint8Array, key: CryptoKey): Promise<string>;
4
+ export declare function decryptSeed(payloadHex: string, key: CryptoKey): Promise<Uint8Array>;
5
+ /**
6
+ * Derive an AES-GCM key from secret input keying material (HKDF-SHA256).
7
+ * The IKM must be secret — anything recoverable by a third party (addresses,
8
+ * public keys) gives no protection.
9
+ */
10
+ export declare function deriveKeyFromSecret(ikm: Uint8Array, salt: Uint8Array, info: string): Promise<CryptoKey>;
11
+ /** Derive the seed-encryption key from a passkey PRF output (HKDF). */
12
+ export declare function deriveKeyFromPrf(prfOutput: Uint8Array): Promise<CryptoKey>;
13
+ /** Derive the seed-encryption key from a wallet message signature + stored salt (HKDF). */
14
+ export declare function deriveKeyFromSignature(signature: Uint8Array, salt: Uint8Array): Promise<CryptoKey>;
15
+ /** Derive the seed-encryption key from a password + stored salt (PBKDF2). */
16
+ export declare function deriveKeyFromPassword(password: string, salt: Uint8Array, iterations?: number): Promise<CryptoKey>;
17
+ export declare const PASSWORD_KDF_ITERATIONS = 600000;
@@ -0,0 +1,54 @@
1
+ /** The name whose text record holds the list. */
2
+ export declare const DEFAULT_SITE_ALLOW_LIST_ENS_NAME = "solarpunkid.eth";
3
+ /** The text record key, in the reverse-domain form ENSIP-5 asks of a vendor key. */
4
+ export declare const DEFAULT_SITE_ALLOW_LIST_RECORD_KEY = "buzz.solarpunk.sites";
5
+ /**
6
+ * How long a list read from the chain is trusted before it is read again. A
7
+ * site removed from the record keeps working at most this long on a device
8
+ * that read it before.
9
+ */
10
+ export declare const SITE_ALLOW_LIST_CACHE_MS: number;
11
+ /** The ENS registry, at the same address on every chain ENS is deployed to. */
12
+ export declare const ENS_REGISTRY_ADDRESS = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
13
+ /** Why a site was refused, so a caller can word its own screen. */
14
+ export type SiteRefusal = "not-clean" | "not-listed" | "list-unavailable";
15
+ export type SiteCheck = {
16
+ allowed: true;
17
+ } | {
18
+ allowed: false;
19
+ reason: SiteRefusal;
20
+ message: string;
21
+ };
22
+ export interface SiteAllowList {
23
+ /** Whether `origin`, exactly as the browser reports it, may be served. */
24
+ check(origin: string): Promise<SiteCheck>;
25
+ }
26
+ export interface SiteAllowListSettings {
27
+ /** An Ethereum mainnet JSON-RPC endpoint. Unset, every site is refused. */
28
+ rpcUrl: string | undefined;
29
+ ensName: string;
30
+ recordKey: string;
31
+ /**
32
+ * Origins allowed without the chain, for local work. Local http is accepted
33
+ * here. Only a development build passes any.
34
+ */
35
+ devOrigins?: readonly string[];
36
+ /** Where the read list is kept between loads. Unset, it is kept in memory. */
37
+ storage?: Pick<Storage, "getItem" | "setItem">;
38
+ now?: () => number;
39
+ }
40
+ /** The EIP-137 namehash of a name already in its normalized form. */
41
+ export declare function ensNamehash(name: string): string;
42
+ /**
43
+ * The origins a record names. Entries are separated by white space or commas.
44
+ * An entry that is not a clean https origin is ignored and logged, so one bad
45
+ * entry cannot take the whole list down, and no entry is ever read as a
46
+ * pattern.
47
+ */
48
+ export declare function parseSiteAllowList(record: string): string[];
49
+ /**
50
+ * The allow list for one setting of name, record key and endpoint. One
51
+ * instance per page: it shares a read in flight between the checks that wait
52
+ * on it.
53
+ */
54
+ export declare function createSiteAllowList(settings: SiteAllowListSettings): SiteAllowList;
@@ -0,0 +1,37 @@
1
+ /** The subset of a stamp record the readiness rule is derived from. */
2
+ export interface StampLifetimeFields {
3
+ batchTTL?: number;
4
+ createdAt: number;
5
+ updatedAt?: number;
6
+ /** What the node last said: absent on a record that predates the fields */
7
+ usable?: boolean;
8
+ exists?: boolean;
9
+ }
10
+ /** Why the session refuses to stamp with the record, or `undefined` if it will. */
11
+ export type StampRefusal = "stamp-expired" | "stamp-not-usable";
12
+ /**
13
+ * The readiness rule. Expiry first, because it is the older and the more
14
+ * specific answer; then what the record says about the batch (#765): one the
15
+ * node does not have (`exists: false`) or cannot use (`usable: false`) has its
16
+ * first stamped write refused, which a dApp gating on `canUpload` alone met
17
+ * 30 s later as a timeout. The fields are what the writer last stored — the
18
+ * chain reconcile on drive open refreshes them — not a live reading.
19
+ */
20
+ export declare function stampRefusal(stamp: StampLifetimeFields, now?: number): StampRefusal | undefined;
21
+ /**
22
+ * Remaining lifespan in seconds at `now`: negative once expired, `undefined`
23
+ * when the TTL was never measured.
24
+ */
25
+ export declare function remainingLifespanSeconds(stamp: StampLifetimeFields, now?: number): number | undefined;
26
+ /**
27
+ * Whether the stored lifetime has run out. An unknown lifetime is not
28
+ * expired: refusing to stamp on missing data would turn every legacy record
29
+ * read-only.
30
+ */
31
+ export declare function isStampExpired(stamp: StampLifetimeFields, now?: number): boolean;
32
+ /**
33
+ * Whether two records would age to the same lifetime and refuse the same way
34
+ * — the check a refresh needs to notice a renewal of the SAME batch, which
35
+ * moves only `batchTTL` and `updatedAt`, or a node that has since accepted it.
36
+ */
37
+ export declare function sameStampLifetime(a: StampLifetimeFields | undefined, b: StampLifetimeFields | undefined): boolean;
@@ -0,0 +1,62 @@
1
+ import { VersionedStorageManager } from "./versioned-storage";
2
+ import type { Account, SyncedAccount, ConnectedApp, PostageStamp } from "../types";
3
+ import { type NetworkSettings } from "../schemas";
4
+ /**
5
+ * Serialize the portable projection of an account (`SyncedAccount`) — what
6
+ * backup files and the sync feed carry off the device. Beyond the schema-level
7
+ * absence of the seed vault, it strips the live per-app session material:
8
+ * `appSecret` (the secret the dApp proxy authenticates from, re-derivable from
9
+ * the master key on the next connect) and `connectedUntil` (meaningless without
10
+ * the secret — keeping it would show a "Connected" app that can no longer
11
+ * authenticate).
12
+ */
13
+ export declare function serializeSyncedAccount(data: SyncedAccount): Record<string, unknown>;
14
+ /**
15
+ * Serialize Account for storage (nested: includes its connected apps and
16
+ * postage stamps inline). A signed-out account persists only its minimal
17
+ * remnant — display fields, the encrypted vault, and the encrypted state
18
+ * snapshot — so no synced data (in particular the plaintext `derivationKey`)
19
+ * stays on disk in the clear while signed out.
20
+ */
21
+ export declare function serializeAccount(account: Account): Record<string, unknown>;
22
+ /**
23
+ * Serialize ConnectedApp for storage
24
+ */
25
+ export declare function serializeConnectedApp(app: ConnectedApp): Record<string, unknown>;
26
+ /**
27
+ * A serialized connected app without its per-context session material.
28
+ *
29
+ * `appSecret` is the app's own credential and `connectedUntil` is the deadline
30
+ * of the session that established it — both belong to one context, and neither
31
+ * survives leaving it. Every channel that carries an account to another
32
+ * context strips them here: the popup handshake (`serializeSyncedAccount`)
33
+ * and the account bus (`accountDeltaSnapshot`). The bus receive schema
34
+ * (`BusConnectedAppSchema` in `bus/messages.ts`) omits the same two fields
35
+ * again, so a publisher that forgets this strip is still caught on receive.
36
+ */
37
+ export declare function portableConnectedApp(app: Record<string, unknown>): Record<string, unknown>;
38
+ /**
39
+ * Serialize PostageStamp for storage
40
+ */
41
+ export declare function serializePostageStamp(stamp: PostageStamp): Record<string, unknown>;
42
+ /**
43
+ * Create storage manager for accounts
44
+ */
45
+ export declare function createAccountsStorageManager(): VersionedStorageManager<Account>;
46
+ /**
47
+ * Serialize NetworkSettings for storage
48
+ */
49
+ export declare function serializeNetworkSettings(settings: NetworkSettings): Record<string, unknown>;
50
+ /**
51
+ * Singleton storage manager interface for network settings
52
+ */
53
+ export interface NetworkSettingsStorageManager {
54
+ load(): NetworkSettings | undefined;
55
+ save(settings: NetworkSettings): void;
56
+ clear(): void;
57
+ }
58
+ /**
59
+ * Create storage manager for network settings (singleton)
60
+ * Unlike other storage managers, this stores a single object, not an array
61
+ */
62
+ export declare function createNetworkSettingsStorageManager(): NetworkSettingsStorageManager;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Whether the proxy iframe can read the trusted domain's first-party store —
3
+ * asked BEFORE authentication, because it decides which transport the auth
4
+ * popup has to take (#613).
5
+ *
6
+ * The mirror image of the probe the connect popup already runs: there, the
7
+ * iframe writes a challenge and the popup checks whether it can read it back
8
+ * first-party (`ui/src/lib/stores/connect.svelte.ts`). That answer arrives far
9
+ * too late to choose a transport, so the same question is asked the other way
10
+ * round — the first-party app leaves a marker, and the iframe reads it back.
11
+ *
12
+ * Deliberately NOT any of these:
13
+ *
14
+ * - **`document.hasStorageAccess()`** — measured 2026-08-31 in the
15
+ * `chromium-partitioned` rig: it returns `true` inside a genuinely
16
+ * partitioned frame. It is cookie-scoped, and Chrome partitions storage
17
+ * separately from cookies, so it answers a different question.
18
+ * - **The accounts key.** The proxy writes `swarm-id-accounts` from inside the
19
+ * iframe (`clearAuthData`), and the versioned storage manager can materialise
20
+ * state in a fresh partitioned bucket, so its presence conflates "first-party
21
+ * storage is visible" with "this partition has its own copy".
22
+ * - **The user agent**, which is what this replaces.
23
+ *
24
+ * The marker only ever answers YES with certainty. Absent means "not proven
25
+ * shared" — a partitioned iframe, or a browser that has never had the SwarmID
26
+ * site open at the top level — and the caller treats that as partitioned,
27
+ * which is the safe direction: the delegated transport works in both modes.
28
+ */
29
+ export declare const STORAGE_SHARED_KEY = "swarm-id-first-party";
30
+ /**
31
+ * Leave the marker. Called by the trusted domain's own pages.
32
+ *
33
+ * The framed guard is load-bearing: the proxy route runs the same app shell
34
+ * inside the iframe, and a marker written there would land in the partitioned
35
+ * bucket and make the iframe report itself shared — the one wrong answer this
36
+ * must never give.
37
+ */
38
+ export declare function markFirstPartyStorage(): void;
39
+ /** Whether this context can see the marker a first-party page left. */
40
+ export declare function isStorageShared(): boolean;
@@ -0,0 +1,11 @@
1
+ import type { Bee } from "@ethersphere/bee-js";
2
+ /**
3
+ * Attempt to create a tag for upload progress tracking.
4
+ * Returns the tag UID on success, or undefined if the node
5
+ * does not support tags (e.g., gateway nodes return 404).
6
+ *
7
+ * Only a definitive 404 (the endpoint is unsupported) is cached per `Bee`; a
8
+ * transient failure (5xx / network / timeout) is NOT cached, so a later upload
9
+ * re-probes the node instead of being permanently tag-less after one blip.
10
+ */
11
+ export declare function tryCreateTag(bee: Bee): Promise<number | undefined>;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * TTL (Time To Live) calculation and formatting utilities for postage stamps
3
+ */
4
+ /**
5
+ * Gnosis Chain block time in seconds
6
+ */
7
+ export declare const GNOSIS_BLOCK_TIME = 5;
8
+ /**
9
+ * Blocks per day on Gnosis Chain (24h / 5s block time = 17280). BigInt so it
10
+ * composes with the PLUR-denominated price math in
11
+ * {@link calculateStampAmountForDays} without precision loss.
12
+ */
13
+ export declare const BLOCKS_PER_DAY: bigint;
14
+ /**
15
+ * Swarmscan API URL for price data
16
+ */
17
+ export declare const SWARMSCAN_STATS_URL = "https://api.swarmscan.io/v1/postage-stamps/stats";
18
+ /**
19
+ * Fetches current price from Swarmscan.
20
+ * @returns pricePerGBPerMonth in BZZ
21
+ */
22
+ export declare function fetchSwarmPrice(): Promise<number>;
23
+ /**
24
+ * Approximates the lifetime of a postage stamp deposit in seconds, assuming
25
+ * the chain's per-block price stays constant at `pricePerGBPerMonth` for the
26
+ * full lifetime. This is the answer to "how long would a stamp with this
27
+ * deposit last at the current price" — not the remaining TTL of an existing
28
+ * stamp (for that, prefer {@link fetchBatchTTL}, which uses live chain state).
29
+ *
30
+ * Uses BigInt math throughout. `pricePerGBPerMonth * 1e16` (PLUR conversion)
31
+ * silently loses precision in Number, since `1e16 > Number.MAX_SAFE_INTEGER`.
32
+ *
33
+ * @param amount - Stamp amount in PLUR (per-chunk)
34
+ * @param pricePerGBPerMonth - Price in BZZ per GiB per month (from Swarmscan)
35
+ * @returns Lifetime in seconds. Returns `0` if the amount or price is
36
+ * non-positive or the price is not finite — a 0-price chain
37
+ * technically never expires stamps, but returning 0 keeps callers
38
+ * inside safe Number range and is the conservative display choice.
39
+ */
40
+ export declare function calculateTTLSeconds(amount: bigint | number | string, pricePerGBPerMonth: number): number;
41
+ /**
42
+ * Formats a TTL value (in seconds) to a human-readable string.
43
+ * Returns "Xd Yh" format (e.g., "30d 14h").
44
+ *
45
+ * @param ttlSeconds - TTL in seconds
46
+ * @returns Human-readable TTL string, or "N/A" if undefined/invalid
47
+ */
48
+ export declare function formatTTL(ttlSeconds: number | undefined): string;
49
+ /**
50
+ * Snapshot of Bee's view of the chain, from `GET /chainstate`.
51
+ *
52
+ * `currentPrice` is PLUR per chunk per block — the per-block storage rent rate
53
+ * Bee charges against a stamp's deposit. Bee returns it as a decimal string
54
+ * because Gnosis prices can exceed `Number.MAX_SAFE_INTEGER` on high-traffic
55
+ * chains, so we keep it BigInt all the way through to the stamp-amount math.
56
+ */
57
+ export interface ChainState {
58
+ block: number;
59
+ currentPrice: bigint;
60
+ }
61
+ /**
62
+ * Fetches the current chain state (block + per-chunk-per-block price) from a
63
+ * Bee node. Used to size new stamp amounts: Bee rejects `POST /stamps` calls
64
+ * whose amount does not cover at least 24h of storage at `currentPrice`.
65
+ *
66
+ * @param beeUrl - Bee node URL
67
+ * @returns Parsed chain state with `currentPrice` as BigInt
68
+ * @throws if the request fails, returns non-OK, or omits required fields.
69
+ * Callers (e.g. the dev page) surface this directly to the user.
70
+ */
71
+ export declare function fetchChainState(beeUrl: string): Promise<ChainState>;
72
+ /**
73
+ * Minimum stamp amount (PLUR per chunk) that covers `days` days of validity
74
+ * at the given per-block price. Bee enforces a 24h floor on `POST /stamps`, so
75
+ * passing `days = 1` returns the exact minimum that will be accepted.
76
+ *
77
+ * @param currentPrice - Per-chunk-per-block price in PLUR (from {@link fetchChainState})
78
+ * @param days - Positive integer number of days of validity to fund
79
+ * @returns Amount in PLUR per chunk, or `0n` for non-positive / non-integer inputs
80
+ */
81
+ export declare function calculateStampAmountForDays(currentPrice: bigint, days: number): bigint;
82
+ /**
83
+ * Live details for a batch from a Bee node's `/stamps/{batchId}` endpoint.
84
+ * Fields are individually optional: each is present only when the response
85
+ * carries it with the expected type.
86
+ */
87
+ export interface BatchDetails {
88
+ /** Remaining TTL in seconds; negative API values are normalised to `0`. */
89
+ batchTTL?: number;
90
+ /** Whether the batch is usable (started and not expired). */
91
+ usable?: boolean;
92
+ /** Whether the batch exists on chain. */
93
+ exists?: boolean;
94
+ }
95
+ /**
96
+ * Fetches live batch details directly from a Bee node's `/stamps/{batchId}`
97
+ * endpoint. The Bee node computes these from current chain state, so they are
98
+ * authoritative — unlike the snapshot stored at stamp-assignment time, which
99
+ * can go stale (e.g. a freshly bought batch reports `usable: false` for ~30s).
100
+ *
101
+ * @param beeUrl - Bee node URL
102
+ * @param batchId - Hex-encoded batch ID (without `0x` prefix)
103
+ * @returns Batch details, or `undefined` if the Bee node does not know about
104
+ * this batch or the request fails.
105
+ */
106
+ export declare function fetchBatchDetails(beeUrl: string, batchId: string): Promise<BatchDetails | undefined>;
107
+ /**
108
+ * Fetches the remaining batchTTL (in seconds) for a stamp directly from a Bee
109
+ * node's `/stamps/{batchId}` endpoint, via {@link fetchBatchDetails}. The Bee
110
+ * node computes this from current chain state (per-block price and cumulative
111
+ * outpayment), so it is more accurate than the constant-price approximation
112
+ * in {@link calculateTTLSeconds}.
113
+ *
114
+ * @param beeUrl - Bee node URL
115
+ * @param batchId - Hex-encoded batch ID (without `0x` prefix)
116
+ * @returns Remaining TTL in seconds, or `undefined` if the Bee node does not
117
+ * know about this batch or the request fails. Negative values from
118
+ * the Bee API are normalised to `0` (expired).
119
+ */
120
+ export declare function fetchBatchTTL(beeUrl: string, batchId: string): Promise<number | undefined>;
@@ -0,0 +1,55 @@
1
+ import type { AppMetadata } from "../types";
2
+ /**
3
+ * Normalize a URL by removing trailing slash.
4
+ */
5
+ export declare function normalizeUrl(url: string): string;
6
+ /**
7
+ * True only for a well-formed `http:`/`https:` URL. Unlike a bare
8
+ * `new URL(value)` / zod `.url()` check, this rejects a scheme-less paste like
9
+ * `localhost:1633` (which `new URL` happily parses with protocol `localhost:`)
10
+ * — the single validator shared by the network-settings schema and its editor
11
+ * dialog so a broken Bee/RPC endpoint can't be saved or persisted.
12
+ */
13
+ export declare function isHttpUrl(value: string): boolean;
14
+ /**
15
+ * True for an address a site may name as its Bee node: an `http:` or
16
+ * `https:` URL, optionally with a path, the way a gateway in front of Bee is
17
+ * often mounted. Refused besides what `isHttpUrl` refuses: credentials, which
18
+ * `fetch` will not send from a URL and throws on, and a query or fragment,
19
+ * which bee-js would put in the middle of every request path it appends.
20
+ */
21
+ export declare function isBeeApiUrl(value: string): boolean;
22
+ /**
23
+ * Configuration options for building the authentication URL.
24
+ */
25
+ export interface BuildAuthUrlOptions {
26
+ /**
27
+ * Challenge string for storage partitioning detection. When present, the popup checks
28
+ * if it can read this challenge from localStorage to determine whether
29
+ * storage is partitioned.
30
+ */
31
+ challenge?: string;
32
+ }
33
+ /**
34
+ * Build the authentication URL for connecting to Swarm ID
35
+ *
36
+ * This function creates the same URL format as used by SwarmIdProxy.openAuthPopup()
37
+ * to ensure consistency across the library.
38
+ *
39
+ * @param baseUrl - The base URL where the authentication page is hosted
40
+ * @param origin - The origin of the parent application requesting authentication
41
+ * @param metadata - Optional application metadata to display during authentication
42
+ * @param options - Optional configuration for the auth URL
43
+ * @returns The complete authentication URL with hash parameters
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const url = buildAuthUrl(
48
+ * "https://swarm-id.example.com",
49
+ * "https://myapp.example.com",
50
+ * { name: "My App", description: "A decentralized application" }
51
+ * )
52
+ * // Returns: "https://swarm-id.example.com/connect#origin=https%3A%2F%2Fmyapp.example.com&appName=My+App&appDescription=A+decentralized+application"
53
+ * ```
54
+ */
55
+ export declare function buildAuthUrl(baseUrl: string, origin: string, metadata?: AppMetadata, options?: BuildAuthUrlOptions): string;