@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
package/dist/schemas.d.ts
CHANGED
|
@@ -59,6 +59,34 @@ export declare const ChatBindingSchema: z.ZodObject<{
|
|
|
59
59
|
message: z.ZodString;
|
|
60
60
|
signature: z.ZodString;
|
|
61
61
|
}, z.core.$strip>;
|
|
62
|
+
/**
|
|
63
|
+
* Longer than any wallet link message can be: five lines, 258 characters,
|
|
64
|
+
* around two addresses and a date. A bound on what is stored and carried, not
|
|
65
|
+
* a check of the format, which `verifyWalletLink` does.
|
|
66
|
+
*/
|
|
67
|
+
export declare const WALLET_LINK_MAX_LENGTH = 320;
|
|
68
|
+
/**
|
|
69
|
+
* The account's and its wallet's statement that they belong together
|
|
70
|
+
* (`utils/wallet-link.ts`, docs/Wallet-Link.md). Kept in the account's synced
|
|
71
|
+
* settings while the person has "Show my ENS name on sites" on, and shared
|
|
72
|
+
* with sites in the connection identity.
|
|
73
|
+
*/
|
|
74
|
+
export declare const WalletLinkSchema: z.ZodObject<{
|
|
75
|
+
message: z.ZodString;
|
|
76
|
+
walletSignature: z.ZodString;
|
|
77
|
+
accountSignature: z.ZodString;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
/**
|
|
80
|
+
* The account's synced settings, one shape for the account record, the state
|
|
81
|
+
* snapshot and the device feed, so a setting one of them does not name is
|
|
82
|
+
* never stripped on the way to another device. The whole object is one
|
|
83
|
+
* last-writer-wins field (`settingsAt`). The wallet link is not in it: it
|
|
84
|
+
* has a clock of its own (`walletLinkAt`), so another device's settings edit
|
|
85
|
+
* can never bring back a link that was turned off.
|
|
86
|
+
*/
|
|
87
|
+
export declare const AccountSettingsSchema: z.ZodObject<{
|
|
88
|
+
appSessionDuration: z.ZodOptional<z.ZodNumber>;
|
|
89
|
+
}, z.core.$strip>;
|
|
62
90
|
/** The stamp choice of an app the person set to use no stamp at all */
|
|
63
91
|
export declare const NO_POSTAGE_STAMP = "none";
|
|
64
92
|
/**
|
|
@@ -236,9 +264,15 @@ export declare const SyncedAccountSchemaV1: z.ZodObject<{
|
|
|
236
264
|
settings: z.ZodOptional<z.ZodObject<{
|
|
237
265
|
appSessionDuration: z.ZodOptional<z.ZodNumber>;
|
|
238
266
|
}, z.core.$strip>>;
|
|
267
|
+
walletLink: z.ZodOptional<z.ZodObject<{
|
|
268
|
+
message: z.ZodString;
|
|
269
|
+
walletSignature: z.ZodString;
|
|
270
|
+
accountSignature: z.ZodString;
|
|
271
|
+
}, z.core.$strip>>;
|
|
239
272
|
accountNameAt: z.ZodOptional<z.ZodNumber>;
|
|
240
273
|
defaultStampAt: z.ZodOptional<z.ZodNumber>;
|
|
241
274
|
settingsAt: z.ZodOptional<z.ZodNumber>;
|
|
275
|
+
walletLinkAt: z.ZodOptional<z.ZodNumber>;
|
|
242
276
|
lastModified: z.ZodOptional<z.ZodNumber>;
|
|
243
277
|
partitionCount: z.ZodOptional<z.ZodNumber>;
|
|
244
278
|
}, z.core.$strip>;
|
|
@@ -303,9 +337,15 @@ declare const SignedInAccountSchemaV1: z.ZodObject<{
|
|
|
303
337
|
settings: z.ZodOptional<z.ZodObject<{
|
|
304
338
|
appSessionDuration: z.ZodOptional<z.ZodNumber>;
|
|
305
339
|
}, z.core.$strip>>;
|
|
340
|
+
walletLink: z.ZodOptional<z.ZodObject<{
|
|
341
|
+
message: z.ZodString;
|
|
342
|
+
walletSignature: z.ZodString;
|
|
343
|
+
accountSignature: z.ZodString;
|
|
344
|
+
}, z.core.$strip>>;
|
|
306
345
|
accountNameAt: z.ZodOptional<z.ZodNumber>;
|
|
307
346
|
defaultStampAt: z.ZodOptional<z.ZodNumber>;
|
|
308
347
|
settingsAt: z.ZodOptional<z.ZodNumber>;
|
|
348
|
+
walletLinkAt: z.ZodOptional<z.ZodNumber>;
|
|
309
349
|
lastModified: z.ZodOptional<z.ZodNumber>;
|
|
310
350
|
partitionCount: z.ZodOptional<z.ZodNumber>;
|
|
311
351
|
signedOutAt: z.ZodOptional<z.ZodUndefined>;
|
|
@@ -428,9 +468,15 @@ export declare const LocalAccountSchemaV1: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
428
468
|
settings: z.ZodOptional<z.ZodObject<{
|
|
429
469
|
appSessionDuration: z.ZodOptional<z.ZodNumber>;
|
|
430
470
|
}, z.core.$strip>>;
|
|
471
|
+
walletLink: z.ZodOptional<z.ZodObject<{
|
|
472
|
+
message: z.ZodString;
|
|
473
|
+
walletSignature: z.ZodString;
|
|
474
|
+
accountSignature: z.ZodString;
|
|
475
|
+
}, z.core.$strip>>;
|
|
431
476
|
accountNameAt: z.ZodOptional<z.ZodNumber>;
|
|
432
477
|
defaultStampAt: z.ZodOptional<z.ZodNumber>;
|
|
433
478
|
settingsAt: z.ZodOptional<z.ZodNumber>;
|
|
479
|
+
walletLinkAt: z.ZodOptional<z.ZodNumber>;
|
|
434
480
|
lastModified: z.ZodOptional<z.ZodNumber>;
|
|
435
481
|
partitionCount: z.ZodOptional<z.ZodNumber>;
|
|
436
482
|
signedOutAt: z.ZodOptional<z.ZodUndefined>;
|
|
@@ -477,9 +523,15 @@ export declare const AccountMetadataSchemaV1: z.ZodObject<{
|
|
|
477
523
|
settings: z.ZodOptional<z.ZodObject<{
|
|
478
524
|
appSessionDuration: z.ZodOptional<z.ZodNumber>;
|
|
479
525
|
}, z.core.$strip>>;
|
|
526
|
+
walletLink: z.ZodOptional<z.ZodObject<{
|
|
527
|
+
message: z.ZodString;
|
|
528
|
+
walletSignature: z.ZodString;
|
|
529
|
+
accountSignature: z.ZodString;
|
|
530
|
+
}, z.core.$strip>>;
|
|
480
531
|
accountNameAt: z.ZodOptional<z.ZodNumber>;
|
|
481
532
|
defaultStampAt: z.ZodOptional<z.ZodNumber>;
|
|
482
533
|
settingsAt: z.ZodOptional<z.ZodNumber>;
|
|
534
|
+
walletLinkAt: z.ZodOptional<z.ZodNumber>;
|
|
483
535
|
createdAt: z.ZodNumber;
|
|
484
536
|
lastModified: z.ZodNumber;
|
|
485
537
|
devices: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -511,9 +563,15 @@ export declare const AccountStateSnapshotSchemaV1: z.ZodObject<{
|
|
|
511
563
|
settings: z.ZodOptional<z.ZodObject<{
|
|
512
564
|
appSessionDuration: z.ZodOptional<z.ZodNumber>;
|
|
513
565
|
}, z.core.$strip>>;
|
|
566
|
+
walletLink: z.ZodOptional<z.ZodObject<{
|
|
567
|
+
message: z.ZodString;
|
|
568
|
+
walletSignature: z.ZodString;
|
|
569
|
+
accountSignature: z.ZodString;
|
|
570
|
+
}, z.core.$strip>>;
|
|
514
571
|
accountNameAt: z.ZodOptional<z.ZodNumber>;
|
|
515
572
|
defaultStampAt: z.ZodOptional<z.ZodNumber>;
|
|
516
573
|
settingsAt: z.ZodOptional<z.ZodNumber>;
|
|
574
|
+
walletLinkAt: z.ZodOptional<z.ZodNumber>;
|
|
517
575
|
createdAt: z.ZodNumber;
|
|
518
576
|
lastModified: z.ZodNumber;
|
|
519
577
|
devices: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -572,6 +630,7 @@ export type SignedOutAccount = z.infer<typeof SignedOutAccountSchemaV1>;
|
|
|
572
630
|
/** The local (on-device) account record: `SignedInAccount | SignedOutAccount`. */
|
|
573
631
|
export type Account = z.infer<typeof LocalAccountSchemaV1>;
|
|
574
632
|
export type ConnectedApp = z.infer<typeof ConnectedAppSchemaV1>;
|
|
633
|
+
export type AccountSettings = z.infer<typeof AccountSettingsSchema>;
|
|
575
634
|
export type PostageStamp = z.infer<typeof PostageStampSchemaV1>;
|
|
576
635
|
export type AccountMetadata = z.infer<typeof AccountMetadataSchemaV1>;
|
|
577
636
|
export type AccountStateSnapshot = z.infer<typeof AccountStateSnapshotSchemaV1>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { SiteAllowList } from "./utils/site-allow-list";
|
|
2
|
+
export interface ButtonFrameConfig {
|
|
3
|
+
/**
|
|
4
|
+
* The sites this frame serves (docs/Site-Allow-List.md), the same list the
|
|
5
|
+
* session frame asks. A site it refuses gets no button.
|
|
6
|
+
*/
|
|
7
|
+
siteAllowList: SiteAllowList;
|
|
8
|
+
/** Take font files over http on localhost, which only a development build does */
|
|
9
|
+
allowLocalHttp?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The visible Swarm ID button a site mounts with `SwarmIdClient.mountButton`.
|
|
13
|
+
*
|
|
14
|
+
* It exists because a frame may open a window only from a click inside it.
|
|
15
|
+
* A site on another site than Swarm ID gets a session frame whose storage is
|
|
16
|
+
* partitioned from the connect window's, so the only way in is a handover the
|
|
17
|
+
* window posts to Swarm ID's frames on the page that opened it, and a window
|
|
18
|
+
* the site's page opens has no such page to post to. The click therefore
|
|
19
|
+
* happens here: this frame opens the window and is its opener, and tells the
|
|
20
|
+
* session frame beside it the window's challenge, so it takes the handover
|
|
21
|
+
* that comes back under it (the window side is `ui/src/lib/handover-targets.ts`).
|
|
22
|
+
* Both frames are Swarm ID's origin under the same top-level site, so they
|
|
23
|
+
* share the partition, and nothing passes the site's page. Every check on the
|
|
24
|
+
* handover stays in the session frame (`SwarmIdProxy.handlePopupMessage`).
|
|
25
|
+
*/
|
|
26
|
+
export declare class SwarmIdButtonFrame {
|
|
27
|
+
private readonly options;
|
|
28
|
+
private readonly container;
|
|
29
|
+
private parentOrigin;
|
|
30
|
+
private identifyReceived;
|
|
31
|
+
private action;
|
|
32
|
+
private config;
|
|
33
|
+
private metadata;
|
|
34
|
+
private popupMode;
|
|
35
|
+
private storageShared;
|
|
36
|
+
private connectWindow;
|
|
37
|
+
private watchStart;
|
|
38
|
+
private watchInterval;
|
|
39
|
+
private button;
|
|
40
|
+
/** Font files asked for, so each is fetched, and reported, once */
|
|
41
|
+
private readonly requestedFonts;
|
|
42
|
+
private readonly onMessage;
|
|
43
|
+
constructor(options: ButtonFrameConfig, container: HTMLElement);
|
|
44
|
+
destroy(): void;
|
|
45
|
+
private handleMessage;
|
|
46
|
+
private handleIdentify;
|
|
47
|
+
private handleUpdate;
|
|
48
|
+
/**
|
|
49
|
+
* Loads the site's font files into this frame. The label already names the
|
|
50
|
+
* family, so it changes once a file arrives, and keeps the fallback family
|
|
51
|
+
* when one does not. The fetch is cross-origin, so the site serves the file
|
|
52
|
+
* with an `Access-Control-Allow-Origin` naming Swarm ID's origin.
|
|
53
|
+
*/
|
|
54
|
+
private loadFontFaces;
|
|
55
|
+
private render;
|
|
56
|
+
/**
|
|
57
|
+
* Opens the connect window from the person's click, which is what lets the
|
|
58
|
+
* browser open it at all. The window looks for the challenge in its own
|
|
59
|
+
* storage to learn whether the session frame reads that storage, so it goes
|
|
60
|
+
* there first only when this frame can open what the first-party pages
|
|
61
|
+
* sealed (`isStorageShared`). Otherwise the window hands the session over,
|
|
62
|
+
* and the session frames are told the challenge once the window is open, so
|
|
63
|
+
* they take the handover that comes back under it.
|
|
64
|
+
*/
|
|
65
|
+
private openConnectWindow;
|
|
66
|
+
private watchWindow;
|
|
67
|
+
private stopWatchingWindow;
|
|
68
|
+
/**
|
|
69
|
+
* Every other frame of the parent page, on Swarm ID's own origin only, so
|
|
70
|
+
* the browser delivers it to Swarm ID's frames and drops it for the site's.
|
|
71
|
+
*/
|
|
72
|
+
private tellSessionFrames;
|
|
73
|
+
private tellWindowState;
|
|
74
|
+
private tellParent;
|
|
75
|
+
}
|
|
76
|
+
/** Starts the button frame, as `initProxy` starts the session frame */
|
|
77
|
+
export declare function initButtonFrame(config: ButtonFrameConfig, container: HTMLElement): SwarmIdButtonFrame;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientOptions, ConnectOptions, AuthStatus, Avatar, ConnectionInfo, UploadResult, FileData, UploadOptions, UploadFilesOptions, CollectionFileInput, CollectionEntry, ActUploadOptions, DownloadOptions, RequestOptions, Reference, SOCReader, SOCWriter, FeedReaderOptions, FeedWriterOptions, FeedReader, FeedWriter, SequentialFeedReaderOptions, SequentialFeedWriterOptions, SequentialFeedReader, SequentialFeedWriter, StampChunkInput, StampedChunk, PostageBatch } from "./types";
|
|
1
|
+
import type { ClientOptions, ConnectOptions, AuthStatus, Avatar, ConnectionInfo, UploadResult, FileData, UploadOptions, UploadFilesOptions, CollectionFileInput, CollectionEntry, ActUploadOptions, DownloadOptions, RequestOptions, Reference, SOCReader, SOCWriter, FeedReaderOptions, FeedWriterOptions, FeedReader, FeedWriter, SequentialFeedReaderOptions, SequentialFeedWriterOptions, SequentialFeedReader, SequentialFeedWriter, StampChunkInput, StampedChunk, MountButtonOptions, MountedButton, PostageBatch } from "./types";
|
|
2
2
|
import { EthAddress, PrivateKey } from "@ethersphere/bee-js";
|
|
3
3
|
/**
|
|
4
4
|
* Main client library for integrating Swarm ID authentication and storage capabilities
|
|
@@ -45,8 +45,8 @@ export declare class SwarmIdClient {
|
|
|
45
45
|
private iframeLoadReject?;
|
|
46
46
|
private popupMode;
|
|
47
47
|
private metadata;
|
|
48
|
-
|
|
49
|
-
private
|
|
48
|
+
/** Each mounted button, with what removes its frame at once */
|
|
49
|
+
private mountedButtons;
|
|
50
50
|
private subsidisedGatewayUrl?;
|
|
51
51
|
private beeApiUrl?;
|
|
52
52
|
private ready;
|
|
@@ -80,22 +80,11 @@ export declare class SwarmIdClient {
|
|
|
80
80
|
* @param options.iframePath - The path to the proxy iframe (defaults to "/proxy")
|
|
81
81
|
* @param options.timeout - Request timeout in milliseconds (defaults to 30000). Bounds each call's whole round trip through the iframe; a call's own `requestOptions.timeout` replaces it for that call
|
|
82
82
|
* @param options.onConnectionChange - Callback invoked when the dApp-visible ConnectionInfo changes (identity, stamp, account type, auth)
|
|
83
|
-
* @param options.popupMode - How
|
|
83
|
+
* @param options.popupMode - How the connect window opens, from {@link connect} or a mounted button: "popup" or "window" (defaults to "window")
|
|
84
84
|
* @param options.metadata - Application metadata shown to users during authentication
|
|
85
85
|
* @param options.metadata.name - Application name (1-100 characters)
|
|
86
86
|
* @param options.metadata.description - Optional application description (max 500 characters)
|
|
87
87
|
* @param options.metadata.icon - Optional application icon as a data URL (SVG or PNG, max 4KB)
|
|
88
|
-
* @param options.buttonConfig - Button configuration for the authentication UI (optional)
|
|
89
|
-
* @param options.buttonConfig.connectText - Text for the connect button (optional)
|
|
90
|
-
* @param options.buttonConfig.disconnectText - Text for the disconnect button (optional)
|
|
91
|
-
* @param options.buttonConfig.loadingText - Text shown during loading (optional)
|
|
92
|
-
* @param options.buttonConfig.backgroundColor - Background color for buttons (optional)
|
|
93
|
-
* @param options.buttonConfig.color - Text color for buttons (optional)
|
|
94
|
-
* @param options.buttonConfig.borderRadius - Border radius for buttons and iframe (optional)
|
|
95
|
-
* @param options.buttonConfig.fontFamily - CSS font-family for the button, so it can match the embedding page; a font stack falls back as usual (optional)
|
|
96
|
-
* @param options.buttonConfig.fontSize - CSS font-size for the button; the default floating iframe is a fixed 300x50 px and hides its overflow, so a size that does not fit is clipped — pass `containerId` to own the box (optional)
|
|
97
|
-
* @param options.buttonConfig.fontWeight - CSS font-weight for the button, as a keyword or a number (optional)
|
|
98
|
-
* @param options.containerId - ID of container element to place iframe in (optional)
|
|
99
88
|
* @param options.subsidisedGatewayUrl - A gateway that stamps uploads for a person with no drive of their own (optional)
|
|
100
89
|
* @param options.beeApiUrl - The Bee node this site's content reads and stamped uploads go through, in place of the person's own setting. Their account and device coordination stay on their own node. Change it later with {@link setBeeApiUrl} (optional)
|
|
101
90
|
* @throws {Error} If constructed where there is no `window` (a server render)
|
|
@@ -112,7 +101,6 @@ export declare class SwarmIdClient {
|
|
|
112
101
|
*
|
|
113
102
|
* @returns A promise that resolves when the client is fully initialized
|
|
114
103
|
* @throws {SwarmIdError} `invalid-state` if the client is already initialized, or `destroy()` runs before it resolves
|
|
115
|
-
* @throws {SwarmIdError} `invalid-request` if `containerId` names no element
|
|
116
104
|
* @throws {SwarmIdError} `init-failed` if the iframe fails to load, origin validation fails on the proxy side, or the proxy does not respond within `initializationTimeout` (30 seconds by default)
|
|
117
105
|
*
|
|
118
106
|
* @example
|
|
@@ -172,25 +160,6 @@ export declare class SwarmIdClient {
|
|
|
172
160
|
* Ensure client is initialized
|
|
173
161
|
*/
|
|
174
162
|
private ensureReady;
|
|
175
|
-
/**
|
|
176
|
-
* Returns the authentication iframe element.
|
|
177
|
-
*
|
|
178
|
-
* The iframe displays authentication UI based on the current auth status:
|
|
179
|
-
* - If not authenticated: shows a "Connect" button
|
|
180
|
-
* - If authenticated: shows identity info and a "Disconnect" button
|
|
181
|
-
*
|
|
182
|
-
* The iframe is positioned fixed in the bottom-right corner of the viewport.
|
|
183
|
-
*
|
|
184
|
-
* @returns The iframe element displaying the authentication UI
|
|
185
|
-
* @throws {SwarmIdError} `invalid-state` if the client is not initialized, or the iframe is not available
|
|
186
|
-
*
|
|
187
|
-
* @example
|
|
188
|
-
* ```typescript
|
|
189
|
-
* const iframe = client.getAuthIframe()
|
|
190
|
-
* // The iframe is already displayed; this returns a reference to it
|
|
191
|
-
* ```
|
|
192
|
-
*/
|
|
193
|
-
getAuthIframe(): HTMLIFrameElement;
|
|
194
163
|
/**
|
|
195
164
|
* Checks the current authentication status with the Swarm ID proxy.
|
|
196
165
|
*
|
|
@@ -280,52 +249,78 @@ export declare class SwarmIdClient {
|
|
|
280
249
|
*/
|
|
281
250
|
disconnect(): Promise<void>;
|
|
282
251
|
/**
|
|
283
|
-
* Opens the Swarm ID
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* - Partitioned, or not proven shared: the proxy opens it, so the popup's
|
|
296
|
-
* `window.opener` points back at the iframe and the session can be handed
|
|
297
|
-
* over directly — the only channel into a partitioned frame. The session
|
|
298
|
-
* is then kept in that partition's own store until it is disconnected or
|
|
299
|
-
* its 7 days are up (#635), so a reload does not re-run this; a handover
|
|
300
|
-
* that arrives without the account view is refused outright rather than
|
|
301
|
-
* producing a session that cannot upload and cannot hear a revoke. A popup
|
|
302
|
-
* blocked on this path falls back to opening from the parent.
|
|
303
|
-
*
|
|
304
|
-
* Safari private mode sessions are ephemeral (lost when the private window
|
|
305
|
-
* closes). The whole partitioned path — handover, stamper, upload — is
|
|
306
|
-
* confirmed on real Safari; see
|
|
307
|
-
* https://github.com/snaha/swarm-id/issues/584
|
|
252
|
+
* Opens the Swarm ID connect window from the site's own control, where the
|
|
253
|
+
* session frame shares Swarm ID's storage: a site on the same site as Swarm
|
|
254
|
+
* ID, such as a self-hosted copy on the site's own domain. The window
|
|
255
|
+
* writes the connection to that storage and the session frame picks it up.
|
|
256
|
+
*
|
|
257
|
+
* Anywhere else the browser partitions the session frame's storage, and the
|
|
258
|
+
* session can reach it only through a window a Swarm ID frame opened from a
|
|
259
|
+
* click inside it. A window opened from here would end on "Connected" with
|
|
260
|
+
* the site still signed out, so this refuses instead and the site shows
|
|
261
|
+
* {@link mountButton}'s button. `connectionInfo.storagePartitioned` and the
|
|
262
|
+
* error's code tell the two apart. The button works in both cases, so a
|
|
263
|
+
* site that always mounts it never needs this.
|
|
308
264
|
*
|
|
309
265
|
* @param options - Configuration options for the connect flow
|
|
310
266
|
* @throws {SwarmIdError} `invalid-state` if the client is not initialized
|
|
311
|
-
* @throws {SwarmIdError} `
|
|
267
|
+
* @throws {SwarmIdError} `button-required` if the session frame's storage is partitioned, or not proven shared
|
|
268
|
+
* @throws {SwarmIdError} `popup-blocked` if the browser blocks the window
|
|
312
269
|
*
|
|
313
270
|
* @example
|
|
314
271
|
* ```typescript
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
272
|
+
* try {
|
|
273
|
+
* await client.connect()
|
|
274
|
+
* } catch (error) {
|
|
275
|
+
* if (error instanceof SwarmIdError && error.code === 'button-required') {
|
|
276
|
+
* client.mountButton(container, { action: 'sign-in' })
|
|
277
|
+
* }
|
|
278
|
+
* }
|
|
320
279
|
* ```
|
|
321
280
|
*/
|
|
322
281
|
connect(options?: ConnectOptions): Promise<void>;
|
|
323
282
|
/**
|
|
324
|
-
*
|
|
283
|
+
* Shows a Swarm ID button in `container`: a small frame of Swarm ID's own,
|
|
284
|
+
* apart from the hidden session frame, that fills the container. Its click
|
|
285
|
+
* opens the connect window, which hands the session to the site's Swarm ID
|
|
286
|
+
* frames, and the site hears of it on {@link ClientOptions.onConnectionChange} as from
|
|
287
|
+
* any sign-in. This is how a person signs in, or changes the stamp the
|
|
288
|
+
* site uses, wherever the site and Swarm ID are on different sites.
|
|
289
|
+
*
|
|
290
|
+
* Unmounting removes only the button, at any time. The session stays, and
|
|
291
|
+
* signing out stays {@link disconnect}. A button unmounted while its window
|
|
292
|
+
* is open stays hidden until the window closes, because the window reads
|
|
293
|
+
* from it, as it opens, where to hand the session. Unmounting it, or
|
|
294
|
+
* removing its container, in the moment between the click and the window
|
|
295
|
+
* opening loses that sign-in, and the person signs in again.
|
|
296
|
+
*
|
|
297
|
+
* @param container - The element the button fills. Give it the size the button should have
|
|
298
|
+
* @param options.action - `sign-in`, or `change-stamp` for a person signed in
|
|
299
|
+
* @param options.config - The label, its busy and disabled states, colours and typography
|
|
300
|
+
* @param options.onWindowChange - Called with `open`, `closed` or `blocked` for the button's connect window
|
|
301
|
+
* @returns The button: `ready`, `update()` and `unmount()`, where `update()` refuses a bad value the same way
|
|
302
|
+
* @throws {SwarmIdError} `invalid-state` if the client is not initialized
|
|
303
|
+
* @throws {SwarmIdError} `invalid-request` if `action` or a `config` value is not one the button takes, naming the field
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const button = client.mountButton(document.getElementById('sign-in')!, {
|
|
308
|
+
* action: 'sign-in',
|
|
309
|
+
* config: { text: 'Sign in', backgroundColor: '#000', borderRadius: '6px' },
|
|
310
|
+
* })
|
|
311
|
+
* await button.ready
|
|
312
|
+
* // later, closing the panel it sits in
|
|
313
|
+
* button.unmount()
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
mountButton(container: HTMLElement, options: MountButtonOptions): MountedButton;
|
|
317
|
+
/**
|
|
318
|
+
* Open the connect window from the site's page, for a session frame that
|
|
319
|
+
* shares Swarm ID's storage.
|
|
325
320
|
*
|
|
326
|
-
* Carries no challenge: a
|
|
321
|
+
* Carries no challenge: a window opened here has the site's page as its
|
|
327
322
|
* `window.opener`, so there is nothing for a handover to attach to, and the
|
|
328
|
-
*
|
|
323
|
+
* window writes the connection to the storage the session frame reads.
|
|
329
324
|
*
|
|
330
325
|
* @returns whether the popup opened — a blocked one returns null, which the
|
|
331
326
|
* caller must not report as a connect in progress.
|
package/dist/swarm-id-proxy.d.ts
CHANGED
|
@@ -8,7 +8,8 @@ export declare const PUBLISH_DEBOUNCE_MS = 1500;
|
|
|
8
8
|
* Swarm ID Proxy - Runs inside the iframe
|
|
9
9
|
*
|
|
10
10
|
* Responsibilities:
|
|
11
|
-
* - Receive app-specific secrets from
|
|
11
|
+
* - Receive app-specific secrets from the connect popup the button frame beside
|
|
12
|
+
* it opened, under the challenge that frame told it
|
|
12
13
|
* - Keep a partitioned session in this partition's own localStorage (#635)
|
|
13
14
|
* - Proxy Bee API calls from parent dApp
|
|
14
15
|
* - Augment requests with authentication
|
|
@@ -25,7 +26,6 @@ export declare class SwarmIdProxy {
|
|
|
25
26
|
private parentIdentifyReceived;
|
|
26
27
|
private siteAllowList;
|
|
27
28
|
private authenticated;
|
|
28
|
-
private authLoading;
|
|
29
29
|
private appSecret;
|
|
30
30
|
/**
|
|
31
31
|
* The chat binding the popup handed over with this session, already checked
|
|
@@ -65,6 +65,12 @@ export declare class SwarmIdProxy {
|
|
|
65
65
|
* first-class writer despite the partition (docs/Account-Bus.md, phase 3).
|
|
66
66
|
*/
|
|
67
67
|
private partitionAccount;
|
|
68
|
+
/**
|
|
69
|
+
* Set while a restored session's saved wallet link is unconfirmed, and kept
|
|
70
|
+
* out of the identity until then (docs/Wallet-Link.md). Cleared by the
|
|
71
|
+
* account's published state, a peer's `account-delta` or a new handover.
|
|
72
|
+
*/
|
|
73
|
+
private walletLinkUnconfirmed;
|
|
68
74
|
/** Account-derived topic the attached bus transports share; undefined when
|
|
69
75
|
* none are attached. */
|
|
70
76
|
private busTopic;
|
|
@@ -127,9 +133,6 @@ export declare class SwarmIdProxy {
|
|
|
127
133
|
private gnosisRpcUrl;
|
|
128
134
|
private postageStampContractAddress;
|
|
129
135
|
private signalingUrl;
|
|
130
|
-
private authButtonContainer;
|
|
131
|
-
private buttonConfig;
|
|
132
|
-
private popupMode;
|
|
133
136
|
private appMetadata;
|
|
134
137
|
/**
|
|
135
138
|
* Bee clients by the URL they were asked for. Keyed on that input URL, not
|
|
@@ -139,7 +142,6 @@ export declare class SwarmIdProxy {
|
|
|
139
142
|
private unsubscribeStorageListeners;
|
|
140
143
|
private storageWorkQueue;
|
|
141
144
|
private lastConnectionInfo;
|
|
142
|
-
private isConnecting;
|
|
143
145
|
private parentWindow;
|
|
144
146
|
private bus;
|
|
145
147
|
/** Who else is live in the account's room, from their `presence` beats. */
|
|
@@ -258,7 +260,8 @@ export declare class SwarmIdProxy {
|
|
|
258
260
|
* Note: We always set up these listeners, even when storage might be partitioned.
|
|
259
261
|
* In some browsers/configurations (like localhost development), storage events
|
|
260
262
|
* work between same-origin windows even in iframes. If storage IS partitioned,
|
|
261
|
-
* the listeners simply won't fire, and
|
|
263
|
+
* the listeners simply won't fire, and the connect popup the button frame
|
|
264
|
+
* opened hands the session over by postMessage instead.
|
|
262
265
|
*/
|
|
263
266
|
private setupStorageListeners;
|
|
264
267
|
/**
|
|
@@ -338,10 +341,22 @@ export declare class SwarmIdProxy {
|
|
|
338
341
|
*/
|
|
339
342
|
private authenticateFromStorage;
|
|
340
343
|
/**
|
|
341
|
-
*
|
|
342
|
-
*
|
|
344
|
+
* A handover from a connect window the button frame beside this one opened.
|
|
345
|
+
* The only way into a session whose storage is partitioned from the
|
|
346
|
+
* window's, where no storage event arrives.
|
|
343
347
|
*/
|
|
344
348
|
private handlePopupMessage;
|
|
349
|
+
/**
|
|
350
|
+
* Whether a message came from another frame of the page this one is in,
|
|
351
|
+
* which is where the button frame sits. A top-level window is not one.
|
|
352
|
+
*/
|
|
353
|
+
private isSiblingFrame;
|
|
354
|
+
/**
|
|
355
|
+
* The button frame beside this one opened a connect window under
|
|
356
|
+
* `challenge`, so the handover that comes back under it is this session's
|
|
357
|
+
* to take. A window opened before it can no longer hand over a stamp.
|
|
358
|
+
*/
|
|
359
|
+
private awaitHandover;
|
|
345
360
|
/**
|
|
346
361
|
* A second handover from the window this session was handed over by,
|
|
347
362
|
* carrying the stamp the person picked there after the first one. Accepted
|
|
@@ -354,24 +369,6 @@ export declare class SwarmIdProxy {
|
|
|
354
369
|
private isStampHandover;
|
|
355
370
|
/** Authenticate in storage-partitioned mode from a checked handover */
|
|
356
371
|
private adoptHandover;
|
|
357
|
-
/**
|
|
358
|
-
* End the connect attempt a refused handover belonged to.
|
|
359
|
-
*
|
|
360
|
-
* The popup cannot be told it was refused — there is no channel back — so it
|
|
361
|
-
* shows "Connected!" while the button here spins on, and the only other
|
|
362
|
-
* thing that ever cleared the flag was the user closing that popup
|
|
363
|
-
* (`checkPopupClosed`), which nothing gave them a reason to do.
|
|
364
|
-
*
|
|
365
|
-
* `isConnecting` first: `showAuthButton` early-returns while it is set, so
|
|
366
|
-
* clearing the flag is what lets the button come back. `authLoading` is
|
|
367
|
-
* already false on every path that reaches here — belt-and-braces, not a
|
|
368
|
-
* second fix.
|
|
369
|
-
*
|
|
370
|
-
* The challenge is deliberately kept. The popup is still open and may yet
|
|
371
|
-
* send a payload this bundle can read; refusing one message ends the
|
|
372
|
-
* attempt's spinner, not the ceremony behind it.
|
|
373
|
-
*/
|
|
374
|
-
private endRefusedConnect;
|
|
375
372
|
/**
|
|
376
373
|
* The handed-over chat binding, if it names exactly this parent origin, the
|
|
377
374
|
* address of the chat key of the secret it came with and the account it came
|
|
@@ -404,7 +401,7 @@ export declare class SwarmIdProxy {
|
|
|
404
401
|
* Re-persist the stored session's account view after a live fold moved it.
|
|
405
402
|
*
|
|
406
403
|
* Without this the record is frozen at the handover: a rotated signer key or
|
|
407
|
-
* a moved
|
|
404
|
+
* a moved pick for this site arrives over the bus, updates `partitionAccount`, and
|
|
408
405
|
* then a reload resurrects the pre-fold copy and uploads with it until the
|
|
409
406
|
* next live overlap.
|
|
410
407
|
*
|
|
@@ -693,6 +690,20 @@ export declare class SwarmIdProxy {
|
|
|
693
690
|
* restored from shared storage does.
|
|
694
691
|
*/
|
|
695
692
|
private restorePartitionSession;
|
|
693
|
+
/**
|
|
694
|
+
* Take the wallet link the account published when it is newer than the
|
|
695
|
+
* restored copy, and tell the site (docs/Wallet-Link.md).
|
|
696
|
+
*
|
|
697
|
+
* The bus carries a change of "Show my ENS name on sites" to a frame that is
|
|
698
|
+
* open, and keeps no mailbox. Turned off while no page of the site was open,
|
|
699
|
+
* the restored copy would go on handing the site the withdrawn wallet, so
|
|
700
|
+
* the published state decides on the link's own clock. Only the link: the
|
|
701
|
+
* rest of the published account still arrives over the bus.
|
|
702
|
+
*
|
|
703
|
+
* Nothing published, or nothing read, confirms nothing, so the restored link
|
|
704
|
+
* stays held back.
|
|
705
|
+
*/
|
|
706
|
+
private foldPublishedWalletLink;
|
|
696
707
|
/**
|
|
697
708
|
* Ask the account's published state whether this restored session was ended
|
|
698
709
|
* while no page of the site was open. Ended means what it means
|
|
@@ -763,10 +774,11 @@ export declare class SwarmIdProxy {
|
|
|
763
774
|
* `buildAccountStateSnapshotForPublish` below — reusing that one would cost
|
|
764
775
|
* two key derivations to send a bus message.
|
|
765
776
|
*
|
|
766
|
-
* `requireDefaultStamp` is the FEED path's precondition, not the snapshot's
|
|
767
|
-
*
|
|
768
|
-
*
|
|
769
|
-
*
|
|
777
|
+
* `requireDefaultStamp` is the FEED path's precondition, not the snapshot's.
|
|
778
|
+
* That write is paid from the drive the person picked for this site, through
|
|
779
|
+
* the coordinator built on the site's resolved stamp, and not from the
|
|
780
|
+
* account default this flag checks. A bus message costs nothing to send and
|
|
781
|
+
* `metadata.defaultPostageStampBatchID` is optional on the wire. An account with no drives is a supported connected state, and
|
|
770
782
|
* gating the delta on a stamp is how such an account's revokes never reach
|
|
771
783
|
* its partitioned sessions at all.
|
|
772
784
|
*/
|
|
@@ -804,7 +816,9 @@ export declare class SwarmIdProxy {
|
|
|
804
816
|
* and to the shared feed via the coordinator (same write lock + held
|
|
805
817
|
* partition). The feed write needs a partition; the bus message does not, so
|
|
806
818
|
* it goes out first and a read-only session still relays to peers that
|
|
807
|
-
* cannot see storage at all.
|
|
819
|
+
* cannot see storage at all. The feed write is paid from the site's picked
|
|
820
|
+
* drive, through the coordinator, and a site with no pick has no coordinator
|
|
821
|
+
* and writes none. Single-device accounts' feeds are published by
|
|
808
822
|
* the SwarmID UI. Re-arms if a publish is already in flight so the latest
|
|
809
823
|
* state still lands.
|
|
810
824
|
*/
|
|
@@ -923,28 +937,6 @@ export declare class SwarmIdProxy {
|
|
|
923
937
|
private handleIsConnected;
|
|
924
938
|
private handleGetNodeInfo;
|
|
925
939
|
private handleDisconnect;
|
|
926
|
-
/**
|
|
927
|
-
* Show authentication button in the UI
|
|
928
|
-
*/
|
|
929
|
-
private showAuthButton;
|
|
930
|
-
private handleConnect;
|
|
931
|
-
/**
|
|
932
|
-
* Open the authentication popup window.
|
|
933
|
-
* Returns true if popup was opened, false if parent origin is not set.
|
|
934
|
-
*/
|
|
935
|
-
private openAuthPopup;
|
|
936
|
-
/**
|
|
937
|
-
* Handle login button click
|
|
938
|
-
*/
|
|
939
|
-
private handleLoginClick;
|
|
940
|
-
/**
|
|
941
|
-
* Handle disconnect button click
|
|
942
|
-
*/
|
|
943
|
-
private handleDisconnectClick;
|
|
944
|
-
/**
|
|
945
|
-
* Set container element for auth button
|
|
946
|
-
*/
|
|
947
|
-
setAuthButtonContainer(container: HTMLElement): void;
|
|
948
940
|
private handleUploadData;
|
|
949
941
|
private handleDownloadData;
|
|
950
942
|
private handleUploadFile;
|