@asseteragmbh/wallet-connector 0.1.2 → 0.2.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.
@@ -16,29 +16,61 @@
16
16
  * origin. The pop-up accepts a message only when `event.origin` is the allowed origin from step 2 AND
17
17
  * `event.source === window.opener`, and answers with `targetOrigin` = that origin. Nothing else is accepted.
18
18
  *
19
+ * ## Sign-in hint
20
+ *
21
+ * A partner may tell the wallet how the client signed in at the partner, through the optional `signIn` URL
22
+ * parameter (`SIGN_IN_HINTS`). The hint only names an identity provider: the wallet checks it against its own
23
+ * list, may ignore it and then falls back to its own login page. The hint never carries a token, an identity or
24
+ * any other credential.
25
+ *
19
26
  * ## Lifetime
20
27
  *
21
- * The pop-up stays open while the partner uses the wallet (ADR-0054, "the wallet tab must stay open"). When it is
22
- * closed, the opener sees `disconnect` (or notices `popup.closed`) and must reconnect from a user click.
28
+ * The pop-up is not guaranteed to stay open. The wallet site may close the `/connect` pop-up after it connected
29
+ * or answered a request. The provider keeps the last `accounts` and `chainId` it saw, so the partner page still
30
+ * looks connected after the pop-up closes, and it opens the pop-up again on the next request from a user click.
31
+ * (ADR-0054, "the wallet tab must stay open", no longer holds.)
23
32
  *
24
33
  * ## Onboarding
25
34
  *
26
- * Onboarding is a second, one-shot flow on the same wallet origin, for a partner that wants to create a brand
27
- * new client wallet rather than connect to an existing one. The partner opens
28
- * `${walletUrl}${ONBOARD_PATH}?origin=<partner origin>&v=<version>&chain=<CAIP-2 chain id>` from a user click.
29
- * The pop-up checks the claimed origin against its partner list, signs the client in through SSO, runs the
30
- * wizard (accept the terms, create the wallet, register it with Compliance, wait for the screening) and then
31
- * posts `onboarded` (or `onboard-cancelled`) to `window.opener` with `targetOrigin` = the partner origin, and
32
- * closes.
35
+ * Onboarding is a second flow on the same wallet origin, for a partner that wants the client to get an Assetera
36
+ * Wallet (a new one, or the one the client already has). The partner opens
37
+ * `${walletUrl}${ONBOARD_PATH}?origin=<partner origin>&v=<version>&chain=<CAIP-2 chain id>[&add=1]` from a user
38
+ * click. The pop-up checks the claimed origin against its partner list, signs the client in through SSO, runs the
39
+ * wizard (accept the wallet terms, create the wallet) and then posts `onboarded` (or `onboard-cancelled`) to
40
+ * `window.opener` with `targetOrigin` = the partner origin. `add=1` asks for one more wallet even when the client
41
+ * already has one.
42
+ *
43
+ * After `onboarded` the pop-up STAYS OPEN and answers `request` messages for `personal_sign` by the onboarded
44
+ * address (plus `eth_accounts` and `eth_chainId`), with the same `response` messages as `/connect`. That is how
45
+ * the partner gets the ownership signature it needs to register the wallet with its own compliance service: the
46
+ * wallet itself never calls a regulated service (ADR-0059 D3), and a second `window.open` after an asynchronous
47
+ * step would be blocked by the browser. The partner closes the pop-up when it is done.
48
+ *
49
+ * The opener accepts messages only when `event.origin` is the wallet origin AND `event.source` is the pop-up
50
+ * it opened. The wizard never returns a private key or a token, only the wallet address and signatures the
51
+ * client approved.
52
+ *
53
+ * ## Manage
33
54
  *
34
- * The opener accepts the result only when `event.origin` is the wallet origin AND `event.source` is the pop-up
35
- * it opened. The wizard never returns a private key or a token, only the resulting wallet address.
55
+ * The partner can open `${walletUrl}${MANAGE_PATH}?origin=<partner origin>&v=<version>[&lang=<locale>][&signIn=<hint>]`
56
+ * from a user click, so the client can see and change the wallet accounts and the wallet security (passkeys,
57
+ * authenticator app, recovery codes). The pop-up checks the claimed origin against its partner list, posts
58
+ * `ready` to `window.opener` (the same message as `/connect`) and then posts `security` messages. It never
59
+ * answers `request` messages.
36
60
  */
37
61
  declare const PROTOCOL_VERSION: 1;
38
62
  /** The pop-up route on the wallet origin. */
39
63
  declare const CONNECT_PATH = "/connect";
40
64
  /** The onboarding wizard route on the wallet origin. */
41
65
  declare const ONBOARD_PATH = "/onboard";
66
+ /** The manage wallet route on the wallet origin. */
67
+ declare const MANAGE_PATH = "/manage";
68
+ /** The identity providers a partner can name in the `signIn` hint. */
69
+ declare const SIGN_IN_HINTS: readonly ["assetera-marketplace"];
70
+ /** A named identity provider the wallet may use for a silent sign-in. */
71
+ type SignInHint = (typeof SIGN_IN_HINTS)[number];
72
+ /** True when `value` is one of {@link SIGN_IN_HINTS}. */
73
+ declare function isSignInHint(value: unknown): value is SignInHint;
42
74
  /** Every message carries this prefix in `type`, so both sides can ignore unrelated `postMessage` traffic. */
43
75
  declare const MESSAGE_PREFIX: "assetera-wallet:";
44
76
  /**
@@ -108,16 +140,48 @@ type EventMessage = {
108
140
  data: RpcError;
109
141
  };
110
142
  /**
111
- * The onboarding wizard finished and the wallet was created (or is still waiting for the Compliance screening).
112
- * `status: "approved"` means the client can transact, `"pending"` means the screening is still running; the
113
- * address is valid in both cases.
143
+ * How well the client's Assetera Wallet is protected. The values are the ones the wallet site shows:
144
+ *
145
+ * - `add-factor`: there is no passkey and no authenticator app yet.
146
+ * - `save-codes`: recovery codes exist, but the client has not confirmed saving them.
147
+ * - `create-codes`: a factor exists, but there are no recovery codes.
148
+ * - `protected`: a factor exists and the recovery codes are saved.
149
+ * - `unknown`: the wallet could not read the state.
150
+ */
151
+ type WalletProtection = "unknown" | "add-factor" | "save-codes" | "create-codes" | "protected";
152
+ /** The wallet security status sent by a manage (or connect) pop-up. */
153
+ interface WalletSecurityStatus {
154
+ /** Overall result, the same values the wallet site shows. */
155
+ protection: WalletProtection;
156
+ /** Passkeys registered for signing (Dynamic step-up), not sign-in factors. */
157
+ passkeys: number;
158
+ /** Authenticator apps (TOTP) registered for signing (Dynamic step-up). */
159
+ authenticatorApps: number;
160
+ }
161
+ /**
162
+ * The wallet reports the security status while a pop-up is open. The partner cannot ask for it. It never
163
+ * carries a token, an identity or a credential.
164
+ */
165
+ interface SecurityMessage {
166
+ type: `${typeof MESSAGE_PREFIX}security`;
167
+ v: typeof PROTOCOL_VERSION;
168
+ data: WalletSecurityStatus;
169
+ }
170
+ /**
171
+ * The onboarding wizard finished: the client accepted the wallet terms and has an Assetera Wallet on `chain`.
172
+ * `created` is `true` when the wallet was created in this run, `false` when the wizard returned the client's
173
+ * existing wallet. The wallet is not registered with any compliance service; that is the partner's step.
114
174
  */
115
175
  interface OnboardedMessage {
116
176
  type: `${typeof MESSAGE_PREFIX}onboarded`;
117
177
  v: typeof PROTOCOL_VERSION;
118
178
  address: `0x${string}`;
119
179
  chain: string;
120
- status: "approved" | "pending";
180
+ created: boolean;
181
+ /**
182
+ * @deprecated Sent by wallet versions that registered the wallet themselves (before ADR-0059). Ignored.
183
+ */
184
+ status?: "approved" | "pending";
121
185
  }
122
186
  /** The onboarding wizard did not produce a wallet. `message` is optional diagnostics for the partner. */
123
187
  interface OnboardCancelledMessage {
@@ -126,7 +190,7 @@ interface OnboardCancelledMessage {
126
190
  reason: "user" | "refused" | "error";
127
191
  message?: string;
128
192
  }
129
- type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | OnboardedMessage | OnboardCancelledMessage;
193
+ type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | SecurityMessage | OnboardedMessage | OnboardCancelledMessage;
130
194
  interface RequestMessage {
131
195
  type: `${typeof MESSAGE_PREFIX}request`;
132
196
  v: typeof PROTOCOL_VERSION;
@@ -144,22 +208,39 @@ type PartnerToWalletMessage = RequestMessage | DisconnectMessage;
144
208
  declare function isReadyMessage(value: unknown): value is ReadyMessage;
145
209
  declare function isResponseMessage(value: unknown): value is ResponseMessage;
146
210
  declare function isEventMessage(value: unknown): value is EventMessage;
211
+ /** True for a `security` message with a known `protection` value and whole, non-negative factor counts. */
212
+ declare function isSecurityMessage(value: unknown): value is SecurityMessage;
147
213
  declare function isRequestMessage(value: unknown): value is RequestMessage;
148
214
  declare function isDisconnectMessage(value: unknown): value is DisconnectMessage;
149
215
  declare function isOnboardedMessage(value: unknown): value is OnboardedMessage;
150
216
  declare function isOnboardCancelledMessage(value: unknown): value is OnboardCancelledMessage;
151
217
  /** A CAIP-2 EVM chain id, for example `eip155:80002` (Polygon Amoy) or `eip155:1` (mainnet). */
152
218
  declare function isCaip2EvmChain(value: string): boolean;
153
- /** The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. */
154
- declare function connectUrl(walletUrl: string, partnerOrigin: string): string;
219
+ /**
220
+ * The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. `signIn` adds the
221
+ * optional sign-in hint; it is only a hint and the wallet may ignore it.
222
+ */
223
+ declare function connectUrl(walletUrl: string, partnerOrigin: string, signIn?: SignInHint): string;
155
224
  /**
156
225
  * The URL the partner opens for the onboarding wizard. `partnerOrigin` is `window.location.origin` of the
157
226
  * partner page; `chain` is the CAIP-2 chain id the new wallet should be created on; `locale` is passed as `lang`
158
- * when the partner wants a specific wizard language.
227
+ * when the partner wants a specific wizard language. `signIn` adds the optional sign-in hint; it is only a hint
228
+ * and the wallet may ignore it.
159
229
  */
160
230
  declare function onboardUrl(walletUrl: string, partnerOrigin: string, options: {
161
231
  chain: string;
162
232
  locale?: string;
233
+ add?: boolean;
234
+ signIn?: SignInHint;
235
+ }): string;
236
+ /**
237
+ * The URL the partner opens to manage the wallet. `partnerOrigin` is `window.location.origin` of the partner
238
+ * page. `locale` is passed as `lang` when the partner wants a specific language. `signIn` adds the optional
239
+ * sign-in hint; it is only a hint and the wallet may ignore it.
240
+ */
241
+ declare function manageUrl(walletUrl: string, partnerOrigin: string, options?: {
242
+ locale?: string;
243
+ signIn?: SignInHint;
163
244
  }): string;
164
245
 
165
- export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SUPPORTED_METHODS, type SupportedMethod, type WalletToPartnerMessage, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSupportedMethod, onboardUrl };
246
+ export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, type SecurityMessage, type SignInHint, type SupportedMethod, type WalletProtection, type WalletSecurityStatus, type WalletToPartnerMessage, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl };
@@ -16,29 +16,61 @@
16
16
  * origin. The pop-up accepts a message only when `event.origin` is the allowed origin from step 2 AND
17
17
  * `event.source === window.opener`, and answers with `targetOrigin` = that origin. Nothing else is accepted.
18
18
  *
19
+ * ## Sign-in hint
20
+ *
21
+ * A partner may tell the wallet how the client signed in at the partner, through the optional `signIn` URL
22
+ * parameter (`SIGN_IN_HINTS`). The hint only names an identity provider: the wallet checks it against its own
23
+ * list, may ignore it and then falls back to its own login page. The hint never carries a token, an identity or
24
+ * any other credential.
25
+ *
19
26
  * ## Lifetime
20
27
  *
21
- * The pop-up stays open while the partner uses the wallet (ADR-0054, "the wallet tab must stay open"). When it is
22
- * closed, the opener sees `disconnect` (or notices `popup.closed`) and must reconnect from a user click.
28
+ * The pop-up is not guaranteed to stay open. The wallet site may close the `/connect` pop-up after it connected
29
+ * or answered a request. The provider keeps the last `accounts` and `chainId` it saw, so the partner page still
30
+ * looks connected after the pop-up closes, and it opens the pop-up again on the next request from a user click.
31
+ * (ADR-0054, "the wallet tab must stay open", no longer holds.)
23
32
  *
24
33
  * ## Onboarding
25
34
  *
26
- * Onboarding is a second, one-shot flow on the same wallet origin, for a partner that wants to create a brand
27
- * new client wallet rather than connect to an existing one. The partner opens
28
- * `${walletUrl}${ONBOARD_PATH}?origin=<partner origin>&v=<version>&chain=<CAIP-2 chain id>` from a user click.
29
- * The pop-up checks the claimed origin against its partner list, signs the client in through SSO, runs the
30
- * wizard (accept the terms, create the wallet, register it with Compliance, wait for the screening) and then
31
- * posts `onboarded` (or `onboard-cancelled`) to `window.opener` with `targetOrigin` = the partner origin, and
32
- * closes.
35
+ * Onboarding is a second flow on the same wallet origin, for a partner that wants the client to get an Assetera
36
+ * Wallet (a new one, or the one the client already has). The partner opens
37
+ * `${walletUrl}${ONBOARD_PATH}?origin=<partner origin>&v=<version>&chain=<CAIP-2 chain id>[&add=1]` from a user
38
+ * click. The pop-up checks the claimed origin against its partner list, signs the client in through SSO, runs the
39
+ * wizard (accept the wallet terms, create the wallet) and then posts `onboarded` (or `onboard-cancelled`) to
40
+ * `window.opener` with `targetOrigin` = the partner origin. `add=1` asks for one more wallet even when the client
41
+ * already has one.
42
+ *
43
+ * After `onboarded` the pop-up STAYS OPEN and answers `request` messages for `personal_sign` by the onboarded
44
+ * address (plus `eth_accounts` and `eth_chainId`), with the same `response` messages as `/connect`. That is how
45
+ * the partner gets the ownership signature it needs to register the wallet with its own compliance service: the
46
+ * wallet itself never calls a regulated service (ADR-0059 D3), and a second `window.open` after an asynchronous
47
+ * step would be blocked by the browser. The partner closes the pop-up when it is done.
48
+ *
49
+ * The opener accepts messages only when `event.origin` is the wallet origin AND `event.source` is the pop-up
50
+ * it opened. The wizard never returns a private key or a token, only the wallet address and signatures the
51
+ * client approved.
52
+ *
53
+ * ## Manage
33
54
  *
34
- * The opener accepts the result only when `event.origin` is the wallet origin AND `event.source` is the pop-up
35
- * it opened. The wizard never returns a private key or a token, only the resulting wallet address.
55
+ * The partner can open `${walletUrl}${MANAGE_PATH}?origin=<partner origin>&v=<version>[&lang=<locale>][&signIn=<hint>]`
56
+ * from a user click, so the client can see and change the wallet accounts and the wallet security (passkeys,
57
+ * authenticator app, recovery codes). The pop-up checks the claimed origin against its partner list, posts
58
+ * `ready` to `window.opener` (the same message as `/connect`) and then posts `security` messages. It never
59
+ * answers `request` messages.
36
60
  */
37
61
  declare const PROTOCOL_VERSION: 1;
38
62
  /** The pop-up route on the wallet origin. */
39
63
  declare const CONNECT_PATH = "/connect";
40
64
  /** The onboarding wizard route on the wallet origin. */
41
65
  declare const ONBOARD_PATH = "/onboard";
66
+ /** The manage wallet route on the wallet origin. */
67
+ declare const MANAGE_PATH = "/manage";
68
+ /** The identity providers a partner can name in the `signIn` hint. */
69
+ declare const SIGN_IN_HINTS: readonly ["assetera-marketplace"];
70
+ /** A named identity provider the wallet may use for a silent sign-in. */
71
+ type SignInHint = (typeof SIGN_IN_HINTS)[number];
72
+ /** True when `value` is one of {@link SIGN_IN_HINTS}. */
73
+ declare function isSignInHint(value: unknown): value is SignInHint;
42
74
  /** Every message carries this prefix in `type`, so both sides can ignore unrelated `postMessage` traffic. */
43
75
  declare const MESSAGE_PREFIX: "assetera-wallet:";
44
76
  /**
@@ -108,16 +140,48 @@ type EventMessage = {
108
140
  data: RpcError;
109
141
  };
110
142
  /**
111
- * The onboarding wizard finished and the wallet was created (or is still waiting for the Compliance screening).
112
- * `status: "approved"` means the client can transact, `"pending"` means the screening is still running; the
113
- * address is valid in both cases.
143
+ * How well the client's Assetera Wallet is protected. The values are the ones the wallet site shows:
144
+ *
145
+ * - `add-factor`: there is no passkey and no authenticator app yet.
146
+ * - `save-codes`: recovery codes exist, but the client has not confirmed saving them.
147
+ * - `create-codes`: a factor exists, but there are no recovery codes.
148
+ * - `protected`: a factor exists and the recovery codes are saved.
149
+ * - `unknown`: the wallet could not read the state.
150
+ */
151
+ type WalletProtection = "unknown" | "add-factor" | "save-codes" | "create-codes" | "protected";
152
+ /** The wallet security status sent by a manage (or connect) pop-up. */
153
+ interface WalletSecurityStatus {
154
+ /** Overall result, the same values the wallet site shows. */
155
+ protection: WalletProtection;
156
+ /** Passkeys registered for signing (Dynamic step-up), not sign-in factors. */
157
+ passkeys: number;
158
+ /** Authenticator apps (TOTP) registered for signing (Dynamic step-up). */
159
+ authenticatorApps: number;
160
+ }
161
+ /**
162
+ * The wallet reports the security status while a pop-up is open. The partner cannot ask for it. It never
163
+ * carries a token, an identity or a credential.
164
+ */
165
+ interface SecurityMessage {
166
+ type: `${typeof MESSAGE_PREFIX}security`;
167
+ v: typeof PROTOCOL_VERSION;
168
+ data: WalletSecurityStatus;
169
+ }
170
+ /**
171
+ * The onboarding wizard finished: the client accepted the wallet terms and has an Assetera Wallet on `chain`.
172
+ * `created` is `true` when the wallet was created in this run, `false` when the wizard returned the client's
173
+ * existing wallet. The wallet is not registered with any compliance service; that is the partner's step.
114
174
  */
115
175
  interface OnboardedMessage {
116
176
  type: `${typeof MESSAGE_PREFIX}onboarded`;
117
177
  v: typeof PROTOCOL_VERSION;
118
178
  address: `0x${string}`;
119
179
  chain: string;
120
- status: "approved" | "pending";
180
+ created: boolean;
181
+ /**
182
+ * @deprecated Sent by wallet versions that registered the wallet themselves (before ADR-0059). Ignored.
183
+ */
184
+ status?: "approved" | "pending";
121
185
  }
122
186
  /** The onboarding wizard did not produce a wallet. `message` is optional diagnostics for the partner. */
123
187
  interface OnboardCancelledMessage {
@@ -126,7 +190,7 @@ interface OnboardCancelledMessage {
126
190
  reason: "user" | "refused" | "error";
127
191
  message?: string;
128
192
  }
129
- type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | OnboardedMessage | OnboardCancelledMessage;
193
+ type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage | SecurityMessage | OnboardedMessage | OnboardCancelledMessage;
130
194
  interface RequestMessage {
131
195
  type: `${typeof MESSAGE_PREFIX}request`;
132
196
  v: typeof PROTOCOL_VERSION;
@@ -144,22 +208,39 @@ type PartnerToWalletMessage = RequestMessage | DisconnectMessage;
144
208
  declare function isReadyMessage(value: unknown): value is ReadyMessage;
145
209
  declare function isResponseMessage(value: unknown): value is ResponseMessage;
146
210
  declare function isEventMessage(value: unknown): value is EventMessage;
211
+ /** True for a `security` message with a known `protection` value and whole, non-negative factor counts. */
212
+ declare function isSecurityMessage(value: unknown): value is SecurityMessage;
147
213
  declare function isRequestMessage(value: unknown): value is RequestMessage;
148
214
  declare function isDisconnectMessage(value: unknown): value is DisconnectMessage;
149
215
  declare function isOnboardedMessage(value: unknown): value is OnboardedMessage;
150
216
  declare function isOnboardCancelledMessage(value: unknown): value is OnboardCancelledMessage;
151
217
  /** A CAIP-2 EVM chain id, for example `eip155:80002` (Polygon Amoy) or `eip155:1` (mainnet). */
152
218
  declare function isCaip2EvmChain(value: string): boolean;
153
- /** The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. */
154
- declare function connectUrl(walletUrl: string, partnerOrigin: string): string;
219
+ /**
220
+ * The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. `signIn` adds the
221
+ * optional sign-in hint; it is only a hint and the wallet may ignore it.
222
+ */
223
+ declare function connectUrl(walletUrl: string, partnerOrigin: string, signIn?: SignInHint): string;
155
224
  /**
156
225
  * The URL the partner opens for the onboarding wizard. `partnerOrigin` is `window.location.origin` of the
157
226
  * partner page; `chain` is the CAIP-2 chain id the new wallet should be created on; `locale` is passed as `lang`
158
- * when the partner wants a specific wizard language.
227
+ * when the partner wants a specific wizard language. `signIn` adds the optional sign-in hint; it is only a hint
228
+ * and the wallet may ignore it.
159
229
  */
160
230
  declare function onboardUrl(walletUrl: string, partnerOrigin: string, options: {
161
231
  chain: string;
162
232
  locale?: string;
233
+ add?: boolean;
234
+ signIn?: SignInHint;
235
+ }): string;
236
+ /**
237
+ * The URL the partner opens to manage the wallet. `partnerOrigin` is `window.location.origin` of the partner
238
+ * page. `locale` is passed as `lang` when the partner wants a specific language. `signIn` adds the optional
239
+ * sign-in hint; it is only a hint and the wallet may ignore it.
240
+ */
241
+ declare function manageUrl(walletUrl: string, partnerOrigin: string, options?: {
242
+ locale?: string;
243
+ signIn?: SignInHint;
163
244
  }): string;
164
245
 
165
- export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SUPPORTED_METHODS, type SupportedMethod, type WalletToPartnerMessage, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSupportedMethod, onboardUrl };
246
+ export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, type OnboardCancelledMessage, type OnboardedMessage, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, type SecurityMessage, type SignInHint, type SupportedMethod, type WalletProtection, type WalletSecurityStatus, type WalletToPartnerMessage, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl };
package/dist/protocol.js CHANGED
@@ -1,3 +1,3 @@
1
- export { CONNECT_PATH, MESSAGE_PREFIX, ONBOARD_PATH, PROTOCOL_VERSION, RpcErrorCode, SUPPORTED_METHODS, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSupportedMethod, onboardUrl } from './chunk-FRKTOKLC.js';
1
+ export { CONNECT_PATH, MANAGE_PATH, MESSAGE_PREFIX, ONBOARD_PATH, PROTOCOL_VERSION, RpcErrorCode, SIGN_IN_HINTS, SUPPORTED_METHODS, connectUrl, isCaip2EvmChain, isDisconnectMessage, isEventMessage, isOnboardCancelledMessage, isOnboardedMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSecurityMessage, isSignInHint, isSupportedMethod, manageUrl, onboardUrl } from './chunk-H7PEM735.js';
2
2
  //# sourceMappingURL=protocol.js.map
3
3
  //# sourceMappingURL=protocol.js.map
@@ -1,10 +1,20 @@
1
+ import { WalletSecurityStatus, SignInHint } from './protocol.cjs';
2
+
3
+ /**
4
+ * EIP-1193 provider for the Assetera Wallet pop-up — the opener side of the ADR-0054 D3/D4 protocol.
5
+ *
6
+ * The provider owns a single pop-up (`window.open(connectUrl(...), "assetera-wallet", ...)`) and speaks the
7
+ * wire format defined in `./protocol`. It never touches Dynamic, React, wagmi or viem, so a partner can use it
8
+ * on its own or through the wagmi / RainbowKit adapters in this package.
9
+ */
10
+
1
11
  /** Arguments accepted by `request`, mirroring EIP-1193. */
2
12
  interface RequestArguments {
3
13
  method: string;
4
14
  params?: unknown[] | Record<string, unknown>;
5
15
  }
6
- /** EIP-1193 provider events emitted by the pop-up. */
7
- type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect";
16
+ /** EIP-1193 provider events emitted by the pop-up, plus the wallet security status. */
17
+ type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect" | "assetera_security";
8
18
  /**
9
19
  * Listener shape for EIP-1193 provider events. `never[]` accepts a listener with any concrete parameter list
10
20
  * (for example wagmi's `(accounts: string[]) => void`), while internal emission stays type-safe via a cast.
@@ -16,15 +26,22 @@ interface AsseteraWalletProvider {
16
26
  on(event: ProviderEvent, listener: ProviderListener): void;
17
27
  removeListener(event: ProviderEvent, listener: ProviderListener): void;
18
28
  disconnect(): void;
29
+ /**
30
+ * The last security status reported by a wallet pop-up, or `undefined` when none arrived yet. A closed pop-up
31
+ * does not clear it.
32
+ */
33
+ lastSecurityStatus(): WalletSecurityStatus | undefined;
19
34
  }
20
35
  /** Options for {@link createAsseteraWalletProvider}. */
21
36
  interface AsseteraWalletProviderOptions {
22
- /** Base URL of the wallet origin, e.g. `https://wallet.playground.assetera.com`. */
37
+ /** Base URL of the wallet origin, e.g. `https://wallet.wallet-staging.assetera.com`. */
23
38
  walletUrl: string;
24
39
  /** Chain id used before the wallet reports one, and as the local `eth_chainId` fallback. */
25
40
  defaultChainId: number;
26
41
  /** `window.open` feature string. Defaults to `"popup,width=420,height=720"`. */
27
42
  popupFeatures?: string;
43
+ /** Sign-in hint passed as `signIn`. Only a hint; the wallet may ignore it. */
44
+ signIn?: SignInHint;
28
45
  }
29
46
  /**
30
47
  * EIP-1193 error carrying a JSON-RPC `code` (and optional `data`). This is what every rejected `request`
@@ -1,10 +1,20 @@
1
+ import { WalletSecurityStatus, SignInHint } from './protocol.js';
2
+
3
+ /**
4
+ * EIP-1193 provider for the Assetera Wallet pop-up — the opener side of the ADR-0054 D3/D4 protocol.
5
+ *
6
+ * The provider owns a single pop-up (`window.open(connectUrl(...), "assetera-wallet", ...)`) and speaks the
7
+ * wire format defined in `./protocol`. It never touches Dynamic, React, wagmi or viem, so a partner can use it
8
+ * on its own or through the wagmi / RainbowKit adapters in this package.
9
+ */
10
+
1
11
  /** Arguments accepted by `request`, mirroring EIP-1193. */
2
12
  interface RequestArguments {
3
13
  method: string;
4
14
  params?: unknown[] | Record<string, unknown>;
5
15
  }
6
- /** EIP-1193 provider events emitted by the pop-up. */
7
- type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect";
16
+ /** EIP-1193 provider events emitted by the pop-up, plus the wallet security status. */
17
+ type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect" | "assetera_security";
8
18
  /**
9
19
  * Listener shape for EIP-1193 provider events. `never[]` accepts a listener with any concrete parameter list
10
20
  * (for example wagmi's `(accounts: string[]) => void`), while internal emission stays type-safe via a cast.
@@ -16,15 +26,22 @@ interface AsseteraWalletProvider {
16
26
  on(event: ProviderEvent, listener: ProviderListener): void;
17
27
  removeListener(event: ProviderEvent, listener: ProviderListener): void;
18
28
  disconnect(): void;
29
+ /**
30
+ * The last security status reported by a wallet pop-up, or `undefined` when none arrived yet. A closed pop-up
31
+ * does not clear it.
32
+ */
33
+ lastSecurityStatus(): WalletSecurityStatus | undefined;
19
34
  }
20
35
  /** Options for {@link createAsseteraWalletProvider}. */
21
36
  interface AsseteraWalletProviderOptions {
22
- /** Base URL of the wallet origin, e.g. `https://wallet.playground.assetera.com`. */
37
+ /** Base URL of the wallet origin, e.g. `https://wallet.wallet-staging.assetera.com`. */
23
38
  walletUrl: string;
24
39
  /** Chain id used before the wallet reports one, and as the local `eth_chainId` fallback. */
25
40
  defaultChainId: number;
26
41
  /** `window.open` feature string. Defaults to `"popup,width=420,height=720"`. */
27
42
  popupFeatures?: string;
43
+ /** Sign-in hint passed as `signIn`. Only a hint; the wallet may ignore it. */
44
+ signIn?: SignInHint;
28
45
  }
29
46
  /**
30
47
  * EIP-1193 error carrying a JSON-RPC `code` (and optional `data`). This is what every rejected `request`
@@ -47,10 +47,26 @@ function isResponseMessage(value) {
47
47
  function isEventMessage(value) {
48
48
  return hasType(value, "event") && (value.event === "accountsChanged" || value.event === "chainChanged" || value.event === "disconnect");
49
49
  }
50
- function connectUrl(walletUrl, partnerOrigin) {
50
+ var WALLET_PROTECTIONS = [
51
+ "unknown",
52
+ "add-factor",
53
+ "save-codes",
54
+ "create-codes",
55
+ "protected"
56
+ ];
57
+ function isCount(value) {
58
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
59
+ }
60
+ function isSecurityMessage(value) {
61
+ if (!hasType(value, "security")) return false;
62
+ const data = value.data;
63
+ return isRecord(data) && typeof data.protection === "string" && WALLET_PROTECTIONS.includes(data.protection) && isCount(data.passkeys) && isCount(data.authenticatorApps);
64
+ }
65
+ function connectUrl(walletUrl, partnerOrigin, signIn) {
51
66
  const url = new URL(CONNECT_PATH, walletUrl);
52
67
  url.searchParams.set("origin", partnerOrigin);
53
68
  url.searchParams.set("v", String(PROTOCOL_VERSION));
69
+ if (signIn !== void 0) url.searchParams.set("signIn", signIn);
54
70
  return url.toString();
55
71
  }
56
72
 
@@ -96,6 +112,7 @@ function createAsseteraWalletProvider(options) {
96
112
  let accounts = [];
97
113
  let chainIdHex = null;
98
114
  let walletDisconnected = false;
115
+ let lastSecurity;
99
116
  const pending = /* @__PURE__ */ new Map();
100
117
  const listeners = /* @__PURE__ */ new Map();
101
118
  let closeTimer = null;
@@ -170,7 +187,7 @@ function createAsseteraWalletProvider(options) {
170
187
  }
171
188
  if (typeof window === "undefined") return null;
172
189
  const opened = window.open(
173
- connectUrl(options.walletUrl, window.location.origin),
190
+ connectUrl(options.walletUrl, window.location.origin, options.signIn),
174
191
  POPUP_NAME,
175
192
  popupFeatures
176
193
  );
@@ -221,6 +238,14 @@ function createAsseteraWalletProvider(options) {
221
238
  walletDisconnected = true;
222
239
  emit("disconnect", new ProviderRpcError(message.data.code, message.data.message, message.data.data));
223
240
  }
241
+ function handleSecurityMessage(message) {
242
+ lastSecurity = {
243
+ protection: message.data.protection,
244
+ passkeys: message.data.passkeys,
245
+ authenticatorApps: message.data.authenticatorApps
246
+ };
247
+ emit("assetera_security", lastSecurity);
248
+ }
224
249
  function onWindowMessage(event) {
225
250
  if (event.origin !== walletOrigin) return;
226
251
  if (popup === null || event.source !== popup) return;
@@ -233,6 +258,10 @@ function createAsseteraWalletProvider(options) {
233
258
  handleResponse(data);
234
259
  return;
235
260
  }
261
+ if (isSecurityMessage(data)) {
262
+ handleSecurityMessage(data);
263
+ return;
264
+ }
236
265
  if (isEventMessage(data)) handleEventMessage(data);
237
266
  }
238
267
  if (typeof window !== "undefined") window.addEventListener("message", onWindowMessage);
@@ -305,7 +334,10 @@ function createAsseteraWalletProvider(options) {
305
334
  function removeListener(event, listener) {
306
335
  removeEventListener(event, listener);
307
336
  }
308
- return { request, on, removeListener, disconnect };
337
+ function lastSecurityStatus() {
338
+ return lastSecurity;
339
+ }
340
+ return { request, on, removeListener, disconnect, lastSecurityStatus };
309
341
  }
310
342
 
311
343
  // src/wagmi.ts
@@ -385,7 +417,8 @@ function asseteraWallet(parameters) {
385
417
  if (!provider) {
386
418
  provider = createAsseteraWalletProvider({
387
419
  walletUrl: parameters.walletUrl,
388
- defaultChainId: config.chains[0].id
420
+ defaultChainId: config.chains[0].id,
421
+ ...parameters.signIn === void 0 ? {} : { signIn: parameters.signIn }
389
422
  });
390
423
  }
391
424
  return provider;
@@ -435,7 +468,10 @@ function asseteraRainbowWallet(options) {
435
468
  iconBackground: "#1a1a2e",
436
469
  installed: true,
437
470
  createConnector: (walletDetails) => core.createConnector((config) => ({
438
- ...asseteraWallet({ walletUrl: options.walletUrl })(config),
471
+ ...asseteraWallet({
472
+ walletUrl: options.walletUrl,
473
+ ...options.signIn === void 0 ? {} : { signIn: options.signIn }
474
+ })(config),
439
475
  ...walletDetails
440
476
  }))
441
477
  });