@solarpunkltd/swarm-id 0.8.2 → 0.10.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.
- package/README.md +17 -7
- package/dist/bus/account-bus.d.ts +12 -0
- package/dist/bus/messages.d.ts +12 -0
- package/dist/bus/signaling-transport.d.ts +2 -0
- package/dist/chunks/ccip-BEanftc1.js +2 -0
- package/dist/chunks/ccip-BEanftc1.js.map +1 -0
- package/dist/chunks/{chat-binding-DgECjSWW.js → chat-binding-gSvKTm5l.js} +15 -15
- package/dist/chunks/chat-binding-gSvKTm5l.js.map +1 -0
- package/dist/chunks/index-BbRV2bja.js +2 -0
- package/dist/chunks/index-BbRV2bja.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/internal.d.ts +3 -1
- package/dist/internal.esm.js +1 -1
- package/dist/internal.esm.js.map +1 -1
- package/dist/schemas.d.ts +59 -0
- package/dist/swarm-id-button-frame.d.ts +77 -0
- package/dist/swarm-id-client.d.ts +64 -69
- package/dist/swarm-id-proxy.d.ts +47 -55
- package/dist/swarm-id.esm.js +1 -1
- package/dist/swarm-id.esm.js.map +1 -1
- package/dist/sync/device-state.d.ts +16 -7
- package/dist/sync/index.d.ts +2 -1
- package/dist/sync/published-wallet-link.d.ts +27 -0
- package/dist/types.d.ts +374 -64
- package/dist/utils/button-view.d.ts +16 -0
- package/dist/utils/ens-name.d.ts +33 -0
- package/dist/utils/ens.d.ts +13 -0
- package/dist/utils/json-rpc.d.ts +5 -0
- package/dist/utils/personal-sign.d.ts +17 -0
- package/dist/utils/postage-stamp-association.d.ts +24 -25
- package/dist/utils/site-allow-list.d.ts +0 -4
- package/dist/utils/storage-probe.d.ts +20 -10
- package/dist/utils/wallet-link.d.ts +70 -0
- package/package.json +2 -1
- package/dist/chunks/chat-binding-DgECjSWW.js.map +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long a wallet's answer is kept before the chain is asked again. A name
|
|
3
|
+
* changed on chain shows at most this long after on a page that read it.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ENS_NAME_CACHE_MS: number;
|
|
6
|
+
/**
|
|
7
|
+
* How long a failed read is kept, so a page that shows many senders does not
|
|
8
|
+
* ask a broken or slow endpoint again for every message it renders, while a
|
|
9
|
+
* passing outage still clears soon.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ENS_NAME_FAILURE_CACHE_MS: number;
|
|
12
|
+
export interface EnsNameOptions {
|
|
13
|
+
/** An Ethereum mainnet JSON-RPC endpoint. Empty, no name is ever answered. */
|
|
14
|
+
rpcUrl: string;
|
|
15
|
+
/** Deadline for the whole lookup. Defaults to `CHAIN_READ_TIMEOUT_MS`. */
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The ENS name of `wallet`, when ENS's Universal Resolver answers a primary
|
|
20
|
+
* name whose address record names the wallet back, and the name is already
|
|
21
|
+
* ENSIP-15 normalised. Undefined for no such name and for everything that goes
|
|
22
|
+
* wrong: no endpoint, an endpoint that does not answer in time, an answer that
|
|
23
|
+
* does not decode, a name's offchain gateway that fails. Never throws.
|
|
24
|
+
*
|
|
25
|
+
* An answer, name or no name, is kept in memory for `ENS_NAME_CACHE_MS` per
|
|
26
|
+
* endpoint and wallet, and lookups that arrive together share one read. A
|
|
27
|
+
* failed read answers no name for `ENS_NAME_FAILURE_CACHE_MS`, and the first
|
|
28
|
+
* lookup after that asks again.
|
|
29
|
+
*
|
|
30
|
+
* @param wallet - the wallet's address, in any case, with or without `0x`,
|
|
31
|
+
* such as `verifyWalletLink(...).wallet`
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveVerifiedEnsName(wallet: string, options: EnsNameOptions): Promise<string | undefined>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** The ENS registry, at the same address on every chain ENS is deployed to. */
|
|
2
|
+
export declare const ENS_REGISTRY_ADDRESS = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
|
|
3
|
+
/** How long each read may take. */
|
|
4
|
+
export interface EnsReadOptions {
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
}
|
|
7
|
+
/** The EIP-137 namehash of a name already in its normalized form. */
|
|
8
|
+
export declare function ensNamehash(name: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* The text record `key` of `name`, through the resolver the registry names.
|
|
11
|
+
* @throws when the name has no resolver or the answers do not decode.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readEnsText(rpcUrl: string, name: string, key: string, options: EnsReadOptions): Promise<string>;
|
package/dist/utils/json-rpc.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ export interface JsonRpcOptions {
|
|
|
8
8
|
* RPC". Defaults to the endpoint's origin.
|
|
9
9
|
*/
|
|
10
10
|
label?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The longest response body read, in bytes. A longer body is refused as it
|
|
13
|
+
* streams in, before anything parses it. Unset, the body is read whole.
|
|
14
|
+
*/
|
|
15
|
+
maxBodyBytes?: number;
|
|
11
16
|
}
|
|
12
17
|
/** One call in a batch. Ids are assigned by {@link jsonRpcBatch}. */
|
|
13
18
|
export interface JsonRpcRequest {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign `message` as `personal_sign` does.
|
|
3
|
+
*
|
|
4
|
+
* @param privateKey - bare hex, 32 bytes
|
|
5
|
+
* @returns `0x` + r ‖ s ‖ v, v 27 or 28, s low
|
|
6
|
+
*/
|
|
7
|
+
export declare function personalSign(message: string, privateKey: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* The address that signed `message`, `0x` + 40 lower-case hex characters.
|
|
10
|
+
* A valid signature over a changed message recovers SOME address, so a caller
|
|
11
|
+
* always compares the result with the signer it expects.
|
|
12
|
+
*
|
|
13
|
+
* @param subject - how errors name the signature, e.g. "Chat binding signature"
|
|
14
|
+
* @throws on a signature that is not 65 bytes of 0x hex, has v other than 27
|
|
15
|
+
* or 28, has a high s, or does not recover a public key.
|
|
16
|
+
*/
|
|
17
|
+
export declare function recoverPersonalSigner(message: string, signature: string, subject: string): string;
|
|
@@ -1,40 +1,39 @@
|
|
|
1
|
-
import { type ConnectedApp, type PostageStamp
|
|
1
|
+
import { type ConnectedApp, type PostageStamp } from "../schemas";
|
|
2
2
|
/**
|
|
3
|
-
* Resolve which postage stamp an app
|
|
3
|
+
* Resolve which postage stamp an app uploads with: the one the person picked
|
|
4
|
+
* for it (`postageStampBatchID`), and nothing else.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The account default is never a fallback (Levi's ruling D4, 2026-10-16). A
|
|
7
|
+
* site with no pick, a site set to `NO_POSTAGE_STAMP`, and a site whose
|
|
8
|
+
* picked drive is gone all resolve to no stamp, and the person picks one in
|
|
9
|
+
* Swarm ID. Falling back let a drive bought after the site signed in, or the
|
|
10
|
+
* default left after the picked drive was removed, pay for the site's
|
|
11
|
+
* uploads without the person choosing it.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* candidate instead of failing.
|
|
13
|
+
* A deleted stamp (tombstone) resolves to nothing. An EXPIRED one still
|
|
14
|
+
* resolves: it can be renewed, and the session reports it as expired (#745).
|
|
13
15
|
*
|
|
14
16
|
* Paired with `stampsReachableByApp` below, which decides what a partitioned
|
|
15
|
-
* session may HOLD while this decides what it SPENDS
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* session may HOLD while this decides what it SPENDS, over the same pointer,
|
|
18
|
+
* and deliberately differing on tombstones: this one skips them (a deleted
|
|
19
|
+
* stamp cannot be spent), that one keeps them (a session learns its stamp is
|
|
20
|
+
* deleted no other way). Change the pointer rule in one and the other has to
|
|
21
|
+
* follow, or a session holds a stamp it cannot resolve, or resolves one it
|
|
22
|
+
* was never handed.
|
|
21
23
|
*/
|
|
22
|
-
export declare function resolveStampForApp(app: Pick<ConnectedApp, "postageStampBatchID">,
|
|
24
|
+
export declare function resolveStampForApp(app: Pick<ConnectedApp, "postageStampBatchID">, stamps: PostageStamp[]): PostageStamp | undefined;
|
|
23
25
|
/**
|
|
24
|
-
* The stamps a connected app's session can ever reach: the
|
|
25
|
-
*
|
|
26
|
+
* The stamps a connected app's session can ever reach: the one the person
|
|
27
|
+
* picked for it, and none while that pick waits for the person to confirm it.
|
|
26
28
|
*
|
|
27
29
|
* This is what a PARTITIONED session is handed and allowed to keep (#578). It
|
|
28
30
|
* holds its account view in memory, in a context embedded by an arbitrary dApp
|
|
29
|
-
* page, and it can only ever spend the stamp `resolveStampForApp` picks
|
|
31
|
+
* page, and it can only ever spend the stamp `resolveStampForApp` picks, so
|
|
30
32
|
* the rest of the collection is signer keys it has no use for. Least privilege
|
|
31
33
|
* rather than a broken boundary: an unpartitioned proxy reads the same material
|
|
32
34
|
* out of shared storage, but it does not have to be handed it.
|
|
33
35
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* only the override would turn a recoverable stale pointer into a session that
|
|
37
|
-
* cannot upload at all. Tombstones its pointers still name are kept too — a
|
|
38
|
-
* tombstone is how the session learns the stamp it was spending is deleted.
|
|
36
|
+
* A tombstone the pointer still names is kept: a tombstone is how the session
|
|
37
|
+
* learns the stamp it was spending is deleted.
|
|
39
38
|
*/
|
|
40
|
-
export declare function stampsReachableByApp(app: Pick<ConnectedApp, "postageStampBatchID" | "stampPending">,
|
|
39
|
+
export declare function stampsReachableByApp(app: Pick<ConnectedApp, "postageStampBatchID" | "stampPending">, stamps: PostageStamp[]): PostageStamp[];
|
|
@@ -8,8 +8,6 @@ export declare const DEFAULT_SITE_ALLOW_LIST_RECORD_KEY = "buzz.solarpunk.sites"
|
|
|
8
8
|
* that read it before.
|
|
9
9
|
*/
|
|
10
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
11
|
/** Why a site was refused, so a caller can word its own screen. */
|
|
14
12
|
export type SiteRefusal = "not-clean" | "not-listed" | "list-unavailable";
|
|
15
13
|
export type SiteCheck = {
|
|
@@ -37,8 +35,6 @@ export interface SiteAllowListSettings {
|
|
|
37
35
|
storage?: Pick<Storage, "getItem" | "setItem">;
|
|
38
36
|
now?: () => number;
|
|
39
37
|
}
|
|
40
|
-
/** The EIP-137 namehash of a name already in its normalized form. */
|
|
41
|
-
export declare function ensNamehash(name: string): string;
|
|
42
38
|
/**
|
|
43
39
|
* The origins a record names. Entries are separated by white space or commas.
|
|
44
40
|
* An entry that is not a clean https origin is ignored and logged, so one bad
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Whether
|
|
2
|
+
* Whether a Swarm ID frame can read the trusted domain's first-party store,
|
|
3
3
|
* asked BEFORE authentication, because it decides which transport the auth
|
|
4
|
-
* popup has to take (#613).
|
|
4
|
+
* popup has to take (#613). Both frames a site embeds read it: the session
|
|
5
|
+
* frame, to tell the client whether `connect()` can work, and the button
|
|
6
|
+
* frame, to decide whether to leave the popup's challenge in storage.
|
|
5
7
|
*
|
|
6
8
|
* The mirror image of the probe the connect popup already runs: there, the
|
|
7
|
-
*
|
|
8
|
-
* first-party (`ui/src/lib/stores/connect.svelte.ts`). That answer
|
|
9
|
-
* too late to choose a transport, so the same question is asked
|
|
10
|
-
* round
|
|
9
|
+
* button frame writes a challenge and the popup checks whether it can read it
|
|
10
|
+
* back first-party (`ui/src/lib/stores/connect.svelte.ts`). That answer
|
|
11
|
+
* arrives far too late to choose a transport, so the same question is asked
|
|
12
|
+
* the other way round: the first-party app leaves a marker, and the frames
|
|
13
|
+
* read it back.
|
|
11
14
|
*
|
|
12
15
|
* Deliberately NOT any of these:
|
|
13
16
|
*
|
|
@@ -24,7 +27,14 @@
|
|
|
24
27
|
* The marker only ever answers YES with certainty. Absent means "not proven
|
|
25
28
|
* shared" — a partitioned iframe, or a browser that has never had the SwarmID
|
|
26
29
|
* site open at the top level — and the caller treats that as partitioned,
|
|
27
|
-
* which is the safe direction: the
|
|
30
|
+
* which is the safe direction: the handover through the Swarm ID button works
|
|
31
|
+
* in both modes.
|
|
32
|
+
*
|
|
33
|
+
* The marker is sealed, because the keys in that store are: a frame that sees
|
|
34
|
+
* the store but not the IndexedDB key that opens it sees no session in it.
|
|
35
|
+
* Playwright's WebKit gives a cross-site frame exactly that, one
|
|
36
|
+
* `localStorage` and its own IndexedDB (measured 2026-10-15), and a plain
|
|
37
|
+
* marker had it wait for a storage write it could never read.
|
|
28
38
|
*/
|
|
29
39
|
export declare const STORAGE_SHARED_KEY = "swarm-id-first-party";
|
|
30
40
|
/**
|
|
@@ -35,6 +45,6 @@ export declare const STORAGE_SHARED_KEY = "swarm-id-first-party";
|
|
|
35
45
|
* bucket and make the iframe report itself shared — the one wrong answer this
|
|
36
46
|
* must never give.
|
|
37
47
|
*/
|
|
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
|
|
48
|
+
export declare function markFirstPartyStorage(): Promise<void>;
|
|
49
|
+
/** Whether this context can see, and open, the marker a first-party page left. */
|
|
50
|
+
export declare function isStorageShared(): Promise<boolean>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** The first line, which also versions the format. */
|
|
2
|
+
export declare const WALLET_LINK_TITLE = "Swarm ID wallet link v1";
|
|
3
|
+
/** The second line, what the wallet's owner agrees to, read exactly. */
|
|
4
|
+
export declare const WALLET_LINK_STATEMENT = "I link this wallet to the Swarm ID account below, so sites may show my ENS name beside its messages.";
|
|
5
|
+
/**
|
|
6
|
+
* One spelling per signature, lower case as `personalSign` writes it, so this
|
|
7
|
+
* reader and the chat library's, which signs the link's bytes into each
|
|
8
|
+
* message, accept exactly the same links.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WALLET_LINK_SIGNATURE_PATTERN: RegExp;
|
|
11
|
+
/** A signed link as it travels and is stored. */
|
|
12
|
+
export interface WalletLink {
|
|
13
|
+
message: string;
|
|
14
|
+
/** The wallet's `personal_sign` of `message`, `0x` + r ‖ s ‖ v, 65 bytes. */
|
|
15
|
+
walletSignature: string;
|
|
16
|
+
/** The account key's `personal_sign` of `message`, in the same form. */
|
|
17
|
+
accountSignature: string;
|
|
18
|
+
}
|
|
19
|
+
/** The three fields a link message carries, as the message spells them. */
|
|
20
|
+
export interface WalletLinkFields {
|
|
21
|
+
/** The Swarm ID account's address, `0x` + 40 lower-case hex characters. */
|
|
22
|
+
account: string;
|
|
23
|
+
/** The wallet's address, in the same form. */
|
|
24
|
+
wallet: string;
|
|
25
|
+
/** ISO 8601 UTC, as `Date.prototype.toISOString` writes it. */
|
|
26
|
+
date: string;
|
|
27
|
+
}
|
|
28
|
+
/** A link both signatures were checked for. Its fields are what it names. */
|
|
29
|
+
export type VerifiedWalletLink = WalletLinkFields;
|
|
30
|
+
/** What a link has to name for a reader to accept it. */
|
|
31
|
+
export interface ExpectedWalletLink {
|
|
32
|
+
/** The account the reader expects, in any case, with or without `0x`. */
|
|
33
|
+
account: string;
|
|
34
|
+
}
|
|
35
|
+
/** Build the exact five-line message for these fields. */
|
|
36
|
+
export declare function buildWalletLinkMessage(fields: {
|
|
37
|
+
account: string;
|
|
38
|
+
wallet: string;
|
|
39
|
+
date: Date;
|
|
40
|
+
}): string;
|
|
41
|
+
/**
|
|
42
|
+
* Read the fields out of a link message, refusing every shape but the one
|
|
43
|
+
* `buildWalletLinkMessage` writes: another first line, another statement, a
|
|
44
|
+
* missing or extra line, a trailing newline, an address in another spelling, a date in
|
|
45
|
+
* another form.
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseWalletLinkMessage(message: string): WalletLinkFields;
|
|
48
|
+
/**
|
|
49
|
+
* Check a link and return what it names, or undefined. It is accepted only
|
|
50
|
+
* when the message has exactly the v1 shape, the wallet signature recovers the
|
|
51
|
+
* wallet the message names, the account signature recovers the account the
|
|
52
|
+
* message names, and that account is `expected.account`. Never throws.
|
|
53
|
+
*
|
|
54
|
+
* A wallet whose signature does not recover its own address, such as a
|
|
55
|
+
* smart-contract wallet (ERC-1271), cannot make a link that passes.
|
|
56
|
+
*/
|
|
57
|
+
export declare function verifyWalletLink(link: WalletLink, expected: ExpectedWalletLink): VerifiedWalletLink | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Countersign a message the wallet has already signed, with the account's own
|
|
60
|
+
* key, after checking the message's shape, that the wallet signature recovers
|
|
61
|
+
* the wallet it names, and that it names this key's account.
|
|
62
|
+
*
|
|
63
|
+
* @param accountKey - the account's private key (bare hex), whose address is
|
|
64
|
+
* the account's `id`
|
|
65
|
+
* @param walletSignature - the wallet's `personal_sign` of `message`, already
|
|
66
|
+
* in the canonical 65-byte form with v 27 or 28
|
|
67
|
+
* @throws on any of those checks failing, so no link is ever stored that a
|
|
68
|
+
* reader would refuse.
|
|
69
|
+
*/
|
|
70
|
+
export declare function countersignWalletLink(accountKey: string, message: string, walletSignature: string): WalletLink;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solarpunkltd/swarm-id",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Swarm ID library for authentication and Bee API operations",
|
|
6
6
|
"main": "dist/swarm-id.esm.js",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"@noble/curves": "1.2.0",
|
|
63
63
|
"@noble/hashes": "1.3.2",
|
|
64
64
|
"cafe-utility": "34.0.0",
|
|
65
|
+
"viem": "2.55.13",
|
|
65
66
|
"zod": "4.1.13"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|