@bootnodedev/canton-connect 0.4.0 → 0.5.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 CHANGED
@@ -61,7 +61,7 @@ be present whether or not you set `walletConnectProjectId`. Only the session is
61
61
  import {
62
62
  CantonConnectProvider,
63
63
  useConnect,
64
- useParty,
64
+ useAccount,
65
65
  useWalletStatus,
66
66
  useSignMessage,
67
67
  useExecute,
@@ -78,7 +78,7 @@ function App() {
78
78
 
79
79
  function Dapp() {
80
80
  const { connect, isPending, isConnected, error } = useConnect()
81
- const { party } = useParty()
81
+ const { account } = useAccount()
82
82
  const { isLocked } = useWalletStatus()
83
83
  const { signMessage } = useSignMessage()
84
84
  const { execute } = useExecute()
@@ -99,7 +99,7 @@ function Dapp() {
99
99
  return <p>Wallet locked. Unlock it to continue.</p>
100
100
  }
101
101
 
102
- // ... your dApp: party.partyId, signMessage(text), execute(params), ledgerApi(params)
102
+ // ... your dApp: account.partyId, signMessage(text), execute(params), ledgerApi(params)
103
103
  }
104
104
  ```
105
105
 
@@ -114,7 +114,7 @@ reports it is not authenticated; that is `isLocked`, and it happens after a succ
114
114
  reference gateway also refuses `signMessage` for a local party; `usePartyType().readPartyType()`
115
115
  tells local from external when you ask. The SDK's status carries one `isConnected` flag, so a lock
116
116
  and a wallet-side disconnect look the same
117
- here. `useLedger().isReady` covers both, and `useParty().party` is `undefined` for the duration:
117
+ here. `useLedger().isReady` covers both, and `useAccount().account` is `undefined` for the duration:
118
118
  gate session content on the party, and use `isLocked` only to explain why it went away.
119
119
 
120
120
  ### Connecting through a Wallet Gateway
@@ -2,7 +2,6 @@ import { DappSDK, WalletConnectAdapter } from "@canton-network/dapp-sdk";
2
2
  import { createContext, useCallback, useContext, useEffect, useMemo } from "react";
3
3
  import { assign, enqueueActions, fromCallback, fromPromise, setup, waitFor } from "xstate";
4
4
  import { useActorRef } from "@xstate/react";
5
- import { WALLET_DISABLED_REASON } from "@canton-network/core-types";
6
5
  import { jsx } from "react/jsx-runtime";
7
6
  //#region src/CantonConnectProvider/adapters.ts
8
7
  /** Builds the extra adapters for the SDK: WalletConnect when configured, plus any passed in. */
@@ -68,10 +67,18 @@ var ConnectCancelledError = class extends Error {
68
67
  this.name = "ConnectCancelledError";
69
68
  }
70
69
  };
71
- /** Whether a rejection carries a string `message`, as a JSON-RPC error object does. */
72
- const hasMessage = (cause) => typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string";
70
+ /** Reads the text off a rejection: `message` as JSON-RPC sends it, `details` as the SDK does. */
71
+ const textOf = (cause) => {
72
+ if (typeof cause !== "object" || cause === null) return;
73
+ for (const key of ["message", "details"]) {
74
+ const value = cause[key];
75
+ if (typeof value === "string" && value !== "") return value;
76
+ }
77
+ };
73
78
  /**
74
- * Hands `cause` back as an `Error`, wrapping what a wallet answered with over JSON-RPC.
79
+ * Hands `cause` back as an `Error`, wrapping what a wallet answered with. Nothing a wallet refuses
80
+ * arrives as an `Error`: the window transport rejects with the bare JSON-RPC object, and the SDK's
81
+ * own controller with a `{ status, error, details }` of its own, so both are read here.
75
82
  *
76
83
  * @example
77
84
  * const error = toError(await sdk.signMessage(params).catch((cause: unknown) => cause))
@@ -79,7 +86,7 @@ const hasMessage = (cause) => typeof cause === "object" && cause !== null && "me
79
86
  */
80
87
  const toError = (cause) => {
81
88
  if (cause instanceof Error) return cause;
82
- return new Error(hasMessage(cause) ? cause.message : String(cause), { cause });
89
+ return new Error(textOf(cause) ?? String(cause), { cause });
83
90
  };
84
91
  /** Classifies what `sdk.connect()` threw, so the cancel path is decided once. */
85
92
  const toConnectError = (cause) => {
@@ -102,41 +109,15 @@ const useConnectBridge = (actorRef) => {
102
109
  }, [actorRef]);
103
110
  };
104
111
  //#endregion
105
- //#region src/walletAccount.ts
106
- /** Whether one raw account entry still has ledger rights to act as a party. */
107
- const isUsable = (account) => {
108
- if (account.status === "initialized" || account.status === "removed") return false;
109
- if (account.disabled === true) return account.reason === WALLET_DISABLED_REASON.NO_SIGNING_PROVIDER_MATCHED;
110
- return true;
111
- };
112
- /** Filters a raw account list down to the ones still usable as a party. */
113
- const selectUsableAccounts = (accounts) => accounts.filter(isUsable);
114
- /** Picks the account flagged `primary`, falling back to the first if none is. */
115
- const selectPrimaryAccount = (accounts) => accounts.find((a) => a.primary) ?? accounts[0];
116
- /** Maps one raw account entry to the public `Party` shape the hooks expose. */
117
- const toParty = (account, fallbackNetworkId) => ({
118
- partyId: account.partyId,
119
- networkId: account.networkId ?? fallbackNetworkId,
120
- namespace: account.namespace,
121
- signingProviderId: account.signingProviderId,
122
- ...account.hint === void 0 ? {} : { name: account.hint },
123
- ...account.publicKey === void 0 ? {} : { publicKey: account.publicKey }
124
- });
125
- //#endregion
126
112
  //#region src/machine/accountsActors.ts
127
- /** Narrows a raw wallet-account list to the primary usable party, or none. */
128
- const toWalletAccounts = (accounts, networkId) => {
129
- const primary = selectPrimaryAccount(selectUsableAccounts(accounts));
130
- return { party: primary === void 0 ? void 0 : toParty(primary, networkId) };
131
- };
132
- /** Reads the wallet's account list once and resolves the primary usable party. */
133
- const readAccounts = fromPromise(async ({ input: { sdk, networkId } }) => toWalletAccounts(await sdk.listAccounts(), networkId));
113
+ /** Reads the wallet's account list once and resolves the one it flags primary. */
114
+ const readPrimaryAccount = fromPromise(async ({ input: { sdk } }) => (await sdk.listAccounts()).find((account) => account.primary));
134
115
  /** Forwards the wallet's own account-change pushes into the machine as `accounts.changed`. */
135
- const accountsEvents = fromCallback(({ sendBack, input: { sdk, networkId } }) => {
116
+ const accountsEvents = fromCallback(({ sendBack, input: { sdk } }) => {
136
117
  const listener = (accounts) => {
137
118
  sendBack({
138
119
  type: "accounts.changed",
139
- accounts: toWalletAccounts(accounts, networkId)
120
+ account: accounts.find((one) => one.primary)
140
121
  });
141
122
  };
142
123
  sdk.onAccountsChanged(listener).catch(() => {});
@@ -147,17 +128,17 @@ const accountsEvents = fromCallback(({ sendBack, input: { sdk, networkId } }) =>
147
128
  //#endregion
148
129
  //#region src/machine/accountsMachine.ts
149
130
  /**
150
- * Reads the connected party once, then follows the wallet's own `accounts.changed` pushes.
131
+ * Reads the connected account once, then follows the wallet's own `accounts.changed` pushes.
151
132
  * Invoked as `connectionMachine`'s `accounts` child while a session is authenticated.
152
133
  */
153
134
  const accountsMachine = setup({
154
135
  actors: {
155
- readAccounts,
136
+ readPrimaryAccount,
156
137
  accountsEvents
157
138
  },
158
139
  actions: {
159
- applyAccounts: assign((_, params) => ({
160
- ...params.accounts,
140
+ applyAccount: assign((_, params) => ({
141
+ account: params.account,
161
142
  error: void 0
162
143
  })),
163
144
  assignError: assign((_, params) => ({ error: params.error }))
@@ -170,37 +151,31 @@ const accountsMachine = setup({
170
151
  }).createMachine({
171
152
  context: ({ input }) => ({
172
153
  ...input,
173
- party: void 0,
154
+ account: void 0,
174
155
  error: void 0
175
156
  }),
176
157
  id: "accounts",
177
158
  initial: "reading",
178
159
  invoke: {
179
160
  src: "accountsEvents",
180
- input: ({ context: { sdk, networkId } }) => ({
181
- sdk,
182
- networkId
183
- })
161
+ input: ({ context: { sdk } }) => ({ sdk })
184
162
  },
185
163
  on: { "accounts.changed": {
186
164
  target: ".ready",
187
165
  actions: {
188
- type: "applyAccounts",
189
- params: ({ event: { accounts } }) => ({ accounts })
166
+ type: "applyAccount",
167
+ params: ({ event: { account } }) => ({ account })
190
168
  }
191
169
  } },
192
170
  states: {
193
171
  reading: { invoke: {
194
- src: "readAccounts",
195
- input: ({ context: { sdk, networkId } }) => ({
196
- sdk,
197
- networkId
198
- }),
172
+ src: "readPrimaryAccount",
173
+ input: ({ context: { sdk } }) => ({ sdk }),
199
174
  onDone: {
200
175
  target: "ready",
201
176
  actions: {
202
- type: "applyAccounts",
203
- params: ({ event: { output } }) => ({ accounts: output })
177
+ type: "applyAccount",
178
+ params: ({ event: { output } }) => ({ account: output })
204
179
  }
205
180
  },
206
181
  onError: {
@@ -528,7 +503,7 @@ const connectionMachine = setup({
528
503
  ...input,
529
504
  sdk: input.createSdk(),
530
505
  lastConnectError: void 0,
531
- party: void 0
506
+ account: void 0
532
507
  }),
533
508
  id: "connection",
534
509
  initial: "idle",
@@ -568,19 +543,16 @@ const connectionMachine = setup({
568
543
  states: {
569
544
  authenticated: {
570
545
  initial: "reading",
571
- exit: assign({ party: void 0 }),
546
+ exit: assign({ account: void 0 }),
572
547
  invoke: {
573
548
  src: "accounts",
574
549
  id: "accounts",
575
- input: ({ context }) => ({
576
- sdk: context.sdk,
577
- networkId: context.networkId
578
- }),
550
+ input: ({ context }) => ({ sdk: context.sdk }),
579
551
  onSnapshot: [{
580
552
  guard: ({ event }) => event.snapshot.matches("ready"),
581
553
  target: ".ready",
582
554
  actions: assign(({ event }) => ({
583
- party: event.snapshot.context.party,
555
+ account: event.snapshot.context.account,
584
556
  lastConnectError: void 0
585
557
  }))
586
558
  }, {
@@ -746,8 +718,7 @@ const CantonConnectProvider = ({ config, children }) => {
746
718
  const actorRef = useConnectionActor({
747
719
  createSdk: () => new DappSDK({ walletPicker: config.walletPicker }),
748
720
  initOptions: { additionalAdapters },
749
- guardPicker: config.walletPicker === void 0,
750
- networkId
721
+ guardPicker: config.walletPicker === void 0
751
722
  });
752
723
  const resetConnectError = useCallback(() => actorRef.send({ type: "connectError.reset" }), [actorRef]);
753
724
  const cancelConnect = useCallback(() => actorRef.send({ type: "connect.cancel" }), [actorRef]);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as Party, c as WalletSdk, i as ConnectionSubscription, l as ConnectionInput, n as CantonConnectContextValue, o as PartyType, r as ConnectionStatus, s as TxStatusSnapshot, t as CantonConnectConfig, u as InitOptions } from "./types-CmnMRMoG.js";
1
+ import { a as ConnectionSubscription, c as TxStatusSnapshot, i as ConnectionStatus, l as ConnectionInput, n as CantonConnectConfig, o as DappSdkMethods, r as CantonConnectContextValue, s as PartyType, t as Account, u as InitOptions } from "./types-BgMSHglV.js";
2
2
  import { LedgerApiParams, PrepareExecuteParams, ProviderAdapter } from "@canton-network/dapp-sdk";
3
3
  import { JSX, ReactNode } from "react";
4
4
  //#region src/CantonConnectProvider/index.d.ts
@@ -60,6 +60,32 @@ export declare class ConnectCancelledError extends Error {
60
60
  constructor(cause?: unknown);
61
61
  }
62
62
  //#endregion
63
+ //#region src/hooks/useAccount.d.ts
64
+ /**
65
+ * Return shape of {@link useAccount}. `account` is the one the wallet flags primary, never
66
+ * substituted, and it changes under a live session.
67
+ *
68
+ * @category Hooks
69
+ */
70
+ interface UseAccountResult {
71
+ account: Account | undefined;
72
+ status: ConnectionStatus;
73
+ isConnected: boolean;
74
+ }
75
+ /**
76
+ * The connected account and status, as the wallet reports it. `account` is `undefined` until a
77
+ * connect succeeds, and again whenever a restored session is locked.
78
+ *
79
+ * @throws with no {@link CantonConnectProvider} above it.
80
+ *
81
+ * @example
82
+ * const { account, isConnected } = useAccount()
83
+ * isConnected && <span>{account?.hint}</span>
84
+ *
85
+ * @category Hooks
86
+ */
87
+ export declare const useAccount: () => UseAccountResult;
88
+ //#endregion
63
89
  //#region src/hooks/useConnect.d.ts
64
90
  /**
65
91
  * Return shape of {@link useConnect}.
@@ -80,7 +106,7 @@ interface UseConnectResult {
80
106
  /**
81
107
  * Connects the wallet and reports that transition. `connect` takes no argument: the picker chooses
82
108
  * the wallet, so there is no mode to pass. Gate a pending face on `isPending` and
83
- * session-dependent content on `useParty().party`, not on `isConnected`.
109
+ * session-dependent content on `useAccount().account`, not on `isConnected`.
84
110
  *
85
111
  * @throws with no {@link CantonConnectProvider} above it, as every hook here does.
86
112
  *
@@ -137,7 +163,7 @@ interface UseExecuteResult {
137
163
  }
138
164
  /**
139
165
  * Submits ledger commands and tracks the transaction in `lastTx`, fed by the SDK's `txChanged`
140
- * event. `actAs` defaults to the party `useParty` reports, so a submit acts as the party the UI
166
+ * event. `actAs` defaults to the party `useAccount` reports, so a submit acts as the party the UI
141
167
  * shows rather than the wallet's own primary.
142
168
  *
143
169
  * @throws with no {@link CantonConnectProvider} above it, and from `execute` where nothing is
@@ -182,32 +208,6 @@ interface UseLedgerResult {
182
208
  */
183
209
  export declare const useLedger: () => UseLedgerResult;
184
210
  //#endregion
185
- //#region src/hooks/useParty.d.ts
186
- /**
187
- * Return shape of {@link useParty}. `party` is the primary among the accounts that can act on the
188
- * ledger, so it need not be the one the wallet flags primary, and it changes under a live session.
189
- *
190
- * @category Hooks
191
- */
192
- interface UsePartyResult {
193
- party: Party | undefined;
194
- status: ConnectionStatus;
195
- isConnected: boolean;
196
- }
197
- /**
198
- * The connected account and status. `party` is `undefined` until a connect succeeds, and again
199
- * whenever a restored session is locked.
200
- *
201
- * @throws with no {@link CantonConnectProvider} above it.
202
- *
203
- * @example
204
- * const { party, isConnected } = useParty()
205
- * isConnected && <span>{party?.partyId}</span>
206
- *
207
- * @category Hooks
208
- */
209
- export declare const useParty: () => UsePartyResult;
210
- //#endregion
211
211
  //#region src/hooks/usePartyType.d.ts
212
212
  /**
213
213
  * Return shape of {@link usePartyType}. `readPartyType` throws when nothing is connected or no
@@ -309,7 +309,7 @@ interface MockAccount {
309
309
  /**
310
310
  * Wiring for {@link createMockAdapter}. `id` defaults to `'mock'`, which is the provider id
311
311
  * `createAutoPicker('mock')` matches; `accounts` defaults to one generated account and treats the
312
- * first entry as primary; omitting `networkId` lets `CantonConnectConfig.networkId` apply instead.
312
+ * first entry as primary; `networkId` defaults to `canton:local`.
313
313
  *
314
314
  * @example
315
315
  * const options: CreateMockAdapterOptions = { id: 'mock', accounts: [{ partyId }] }
@@ -343,4 +343,4 @@ interface MockAdapter extends ProviderAdapter {
343
343
  */
344
344
  export declare const createMockAdapter: (options?: CreateMockAdapterOptions) => MockAdapter;
345
345
  //#endregion
346
- export type { CantonConnectConfig, CantonConnectContextValue, CantonConnectProviderProps, ConnectionInput, ConnectionStatus, ConnectionSubscription, CreateMockAdapterOptions, InitOptions, LedgerApiParams, MockAccount, MockAdapter, Party, PartyType, PrepareExecuteParams, TxStatusSnapshot, UseConnectResult, UseDisconnectResult, UseExecuteResult, UseLedgerResult, UsePartyResult, UsePartyTypeResult, UseSignMessageResult, UseWalletStatusResult, WalletSdk };
346
+ export type { Account, CantonConnectConfig, CantonConnectContextValue, CantonConnectProviderProps, ConnectionInput, ConnectionStatus, ConnectionSubscription, CreateMockAdapterOptions, DappSdkMethods, InitOptions, LedgerApiParams, MockAccount, MockAdapter, PartyType, PrepareExecuteParams, TxStatusSnapshot, UseAccountResult, UseConnectResult, UseDisconnectResult, UseExecuteResult, UseLedgerResult, UsePartyTypeResult, UseSignMessageResult, UseWalletStatusResult };
package/dist/index.js CHANGED
@@ -1,11 +1,35 @@
1
- import { a as toConnectionStatus, c as toError, n as CantonConnectProvider, o as ConnectCancelledError, r as useCantonConnectContext, s as toConnectError } from "./CantonConnectProvider-CJ1yWGXz.js";
1
+ import { a as toConnectionStatus, c as toError, n as CantonConnectProvider, o as ConnectCancelledError, r as useCantonConnectContext, s as toConnectError } from "./CantonConnectProvider-M9GvvKOx.js";
2
2
  import { useCallback, useEffect, useMemo, useState } from "react";
3
3
  import { useSelector } from "@xstate/react";
4
+ //#region src/hooks/useAccount.ts
5
+ /**
6
+ * The connected account and status, as the wallet reports it. `account` is `undefined` until a
7
+ * connect succeeds, and again whenever a restored session is locked.
8
+ *
9
+ * @throws with no {@link CantonConnectProvider} above it.
10
+ *
11
+ * @example
12
+ * const { account, isConnected } = useAccount()
13
+ * isConnected && <span>{account?.hint}</span>
14
+ *
15
+ * @category Hooks
16
+ */
17
+ const useAccount = () => {
18
+ const { connection } = useCantonConnectContext();
19
+ const account = useSelector(connection, (snapshot) => snapshot.context.account);
20
+ const status = useSelector(connection, toConnectionStatus);
21
+ return {
22
+ account,
23
+ status,
24
+ isConnected: status === "connected"
25
+ };
26
+ };
27
+ //#endregion
4
28
  //#region src/hooks/useConnect.ts
5
29
  /**
6
30
  * Connects the wallet and reports that transition. `connect` takes no argument: the picker chooses
7
31
  * the wallet, so there is no mode to pass. Gate a pending face on `isPending` and
8
- * session-dependent content on `useParty().party`, not on `isConnected`.
32
+ * session-dependent content on `useAccount().account`, not on `isConnected`.
9
33
  *
10
34
  * @throws with no {@link CantonConnectProvider} above it, as every hook here does.
11
35
  *
@@ -92,9 +116,9 @@ const assertUsable = (status, isLocked) => {
92
116
  if (status !== "connected") throw new Error("wallet is not connected - call useConnect().connect() first");
93
117
  if (isLocked) throw new Error("wallet is locked - unlock it in the wallet");
94
118
  };
95
- /** Throws when the session reports no party, which a connected one can. */
119
+ /** Throws when the session reports no account, which a connected one can. */
96
120
  function assertPartyId(partyId) {
97
- if (partyId === void 0) throw new Error("wallet reports no usable party - allocate one in the wallet");
121
+ if (partyId === void 0) throw new Error("wallet reports no primary account - select or add one in the wallet");
98
122
  }
99
123
  /**
100
124
  * Selects the session and wraps one SDK call with the connect, lock and party guards plus the
@@ -103,7 +127,7 @@ function assertPartyId(partyId) {
103
127
  const useWalletCall = () => {
104
128
  const { connection } = useCantonConnectContext();
105
129
  const sdk = useSelector(connection, (snapshot) => snapshot.context.sdk);
106
- const partyId = useSelector(connection, (snapshot) => snapshot.context.party?.partyId);
130
+ const partyId = useSelector(connection, (snapshot) => snapshot.context.account?.partyId);
107
131
  const status = useSelector(connection, toConnectionStatus);
108
132
  const isLocked = useSelector(connection, (snapshot) => snapshot.hasTag("unauthenticated"));
109
133
  const [state, setState] = useState(IDLE);
@@ -153,7 +177,7 @@ const withActAs = (params, partyId) => params.actAs === void 0 ? {
153
177
  } : params;
154
178
  /**
155
179
  * Submits ledger commands and tracks the transaction in `lastTx`, fed by the SDK's `txChanged`
156
- * event. `actAs` defaults to the party `useParty` reports, so a submit acts as the party the UI
180
+ * event. `actAs` defaults to the party `useAccount` reports, so a submit acts as the party the UI
157
181
  * shows rather than the wallet's own primary.
158
182
  *
159
183
  * @throws with no {@link CantonConnectProvider} above it, and from `execute` where nothing is
@@ -211,30 +235,6 @@ const useLedger = () => {
211
235
  };
212
236
  };
213
237
  //#endregion
214
- //#region src/hooks/useParty.ts
215
- /**
216
- * The connected account and status. `party` is `undefined` until a connect succeeds, and again
217
- * whenever a restored session is locked.
218
- *
219
- * @throws with no {@link CantonConnectProvider} above it.
220
- *
221
- * @example
222
- * const { party, isConnected } = useParty()
223
- * isConnected && <span>{party?.partyId}</span>
224
- *
225
- * @category Hooks
226
- */
227
- const useParty = () => {
228
- const { connection } = useCantonConnectContext();
229
- const party = useSelector(connection, (snapshot) => snapshot.context.party);
230
- const status = useSelector(connection, toConnectionStatus);
231
- return {
232
- party,
233
- status,
234
- isConnected: status === "connected"
235
- };
236
- };
237
- //#endregion
238
238
  //#region src/hooks/usePartyType.ts
239
239
  const namespaceOf = (id) => /::(.+)$/.exec(id)?.[1];
240
240
  const readParticipantNamespace = async (sdk) => {
@@ -265,20 +265,20 @@ const readParticipantNamespace = async (sdk) => {
265
265
  */
266
266
  const usePartyType = () => {
267
267
  const { connection, sdk, status, isLocked } = useWalletCall();
268
- const party = useSelector(connection, (snapshot) => snapshot.context.party);
268
+ const account = useSelector(connection, (snapshot) => snapshot.context.account);
269
269
  return {
270
270
  readPartyType: useCallback(async () => {
271
271
  assertUsable(status, isLocked);
272
- if (party === void 0) throw new Error("wallet reports no usable party - allocate one in the wallet");
272
+ if (account === void 0) throw new Error("wallet reports no primary account - select or add one in the wallet");
273
273
  const participantNamespace = await readParticipantNamespace(sdk);
274
- return party.namespace === participantNamespace ? "local" : "external";
274
+ return account.namespace === participantNamespace ? "local" : "external";
275
275
  }, [
276
+ account,
276
277
  isLocked,
277
- party,
278
278
  sdk,
279
279
  status
280
280
  ]),
281
- isReady: status === "connected" && !isLocked && party !== void 0
281
+ isReady: status === "connected" && !isLocked && account !== void 0
282
282
  };
283
283
  };
284
284
  //#endregion
@@ -341,21 +341,22 @@ const useWalletStatus = () => {
341
341
  const DEFAULT_PROVIDER_ID = "mock";
342
342
  const DEFAULT_NAME = "Mock Wallet";
343
343
  const DEFAULT_DESCRIPTION = "Mock wallet for dev and tests — no real signing, never a live wallet";
344
- const MOCK_WALLET_STATUS = "allocated";
344
+ const MOCK_ACCOUNT_STATUS = "allocated";
345
345
  const MOCK_SIGNING_PROVIDER_ID = "mock";
346
346
  const MOCK_PUBLIC_KEY = "mock-public-key";
347
+ const MOCK_NETWORK_ID = "canton:local";
347
348
  /** The single mock account `createMockAdapter` reports when the caller supplies none. */
348
349
  const defaultAccounts = (providerId) => [{ partyId: `${providerId}::1220abcd` }];
349
- /** Shapes one `MockAccount` into the `Wallet` the mock adapter's `listAccounts` returns. */
350
- const toWallet = (account, primary, networkId) => ({
350
+ /** Shapes one `MockAccount` into the `Account` the mock adapter's `listAccounts` returns. */
351
+ const toAccount = (account, primary, networkId) => ({
351
352
  primary,
352
353
  partyId: account.partyId,
353
- status: MOCK_WALLET_STATUS,
354
+ status: MOCK_ACCOUNT_STATUS,
354
355
  hint: account.name ?? account.partyId,
355
356
  publicKey: account.publicKey ?? MOCK_PUBLIC_KEY,
356
357
  namespace: account.partyId.split("::")[1] ?? account.partyId,
357
- signingProviderId: MOCK_SIGNING_PROVIDER_ID,
358
- ...networkId === void 0 ? {} : { networkId }
358
+ networkId: networkId ?? MOCK_NETWORK_ID,
359
+ signingProviderId: MOCK_SIGNING_PROVIDER_ID
359
360
  });
360
361
  /**
361
362
  * The adapter `createMockAdapter` returns: it announces itself like an installed wallet and
@@ -365,13 +366,13 @@ var MockProviderAdapter = class {
365
366
  providerId;
366
367
  name = DEFAULT_NAME;
367
368
  type = "browser";
368
- wallets;
369
+ accounts;
369
370
  connected = false;
370
371
  listenerMap = {};
371
372
  constructor(options) {
372
373
  this.providerId = options.id ?? DEFAULT_PROVIDER_ID;
373
374
  const accounts = options.accounts ?? defaultAccounts(this.providerId);
374
- this.wallets = accounts.map((account, index) => toWallet(account, index === 0, options.networkId));
375
+ this.accounts = accounts.map((account, index) => toAccount(account, index === 0, options.networkId));
375
376
  }
376
377
  getInfo() {
377
378
  return {
@@ -410,7 +411,7 @@ var MockProviderAdapter = class {
410
411
  isNetworkConnected: true
411
412
  }
412
413
  }),
413
- listAccounts: () => this.wallets
414
+ listAccounts: () => this.accounts
414
415
  };
415
416
  async request(args) {
416
417
  const handler = this.handlers[args.method];
@@ -445,4 +446,4 @@ var MockProviderAdapter = class {
445
446
  */
446
447
  const createMockAdapter = (options = {}) => new MockProviderAdapter(options);
447
448
  //#endregion
448
- export { CantonConnectProvider, ConnectCancelledError, createMockAdapter, useCantonConnectContext, useConnect, useDisconnect, useExecute, useLedger, useParty, usePartyType, useSignMessage, useWalletStatus };
449
+ export { CantonConnectProvider, ConnectCancelledError, createMockAdapter, useAccount, useCantonConnectContext, useConnect, useDisconnect, useExecute, useLedger, usePartyType, useSignMessage, useWalletStatus };
@@ -1,4 +1,4 @@
1
- import { a as Party, c as WalletSdk, r as ConnectionStatus } from "../types-CmnMRMoG.js";
1
+ import { i as ConnectionStatus, o as DappSdkMethods, t as Account } from "../types-BgMSHglV.js";
2
2
  import { WalletPickerFn } from "@canton-network/dapp-sdk";
3
3
  import { JSX, ReactNode } from "react";
4
4
  //#region src/testing/autoPicker.d.ts
@@ -18,19 +18,19 @@ export declare const createAutoPicker: (pick?: string) => WalletPickerFn;
18
18
  //#endregion
19
19
  //#region src/testing/fakeSession.d.ts
20
20
  /**
21
- * Props for {@link FakeSessionProvider}. `status` starts the session mid-flight and `party` is
21
+ * Props for {@link FakeSessionProvider}. `status` starts the session mid-flight and `account` is
22
22
  * what a connect resolves to; `readingAccounts` reaches the pending face over a live session, and
23
23
  * `sdk` drives a hook's own pending, error and `reset()`, never what a wallet returns.
24
24
  *
25
25
  * @category Components
26
26
  */
27
27
  interface FakeSessionProviderProps {
28
+ account?: Account;
28
29
  children: ReactNode;
29
30
  connectError?: Error;
30
31
  isLocked?: boolean;
31
- party?: Party;
32
32
  readingAccounts?: boolean;
33
- sdk?: Partial<WalletSdk>;
33
+ sdk?: Partial<DappSdkMethods>;
34
34
  status?: ConnectionStatus;
35
35
  }
36
36
  /**
@@ -43,19 +43,19 @@ interface FakeSessionProviderProps {
43
43
  *
44
44
  * @example
45
45
  * render(
46
- * <FakeSessionProvider status="connected" party={party}>
46
+ * <FakeSessionProvider status="connected" account={account}>
47
47
  * <ConnectButton />
48
48
  * </FakeSessionProvider>,
49
49
  * )
50
50
  *
51
51
  * @category Components
52
52
  */
53
- export declare const FakeSessionProvider: ({ children, connectError, isLocked, party, readingAccounts, sdk, status: initialStatus }: FakeSessionProviderProps) => JSX.Element;
53
+ export declare const FakeSessionProvider: ({ account, children, connectError, isLocked, readingAccounts, sdk, status: initialStatus }: FakeSessionProviderProps) => JSX.Element;
54
54
  //#endregion
55
55
  //#region src/testing/fakeWallet.d.ts
56
56
  /**
57
57
  * One account the fake wallet reports from `listAccounts`. Mark exactly one `primary`: that is the
58
- * entry `selectPrimaryAccount` resolves to `Party`.
58
+ * entry the session reports.
59
59
  *
60
60
  * @category Utilities
61
61
  */
@@ -1,8 +1,8 @@
1
- import { i as connectionMachine, t as CantonConnectContext } from "../CantonConnectProvider-CJ1yWGXz.js";
1
+ import { i as connectionMachine, t as CantonConnectContext } from "../CantonConnectProvider-M9GvvKOx.js";
2
2
  import { useCallback, useEffect, useMemo, useState } from "react";
3
3
  import { createActor } from "xstate";
4
- import { CANTON_ANNOUNCE_PROVIDER_EVENT, CANTON_REQUEST_PROVIDER_EVENT, WalletEvent } from "@canton-network/core-types";
5
4
  import { jsx } from "react/jsx-runtime";
5
+ import { CANTON_ANNOUNCE_PROVIDER_EVENT, CANTON_REQUEST_PROVIDER_EVENT, WalletEvent } from "@canton-network/core-types";
6
6
  //#region src/testing/autoPicker.ts
7
7
  /**
8
8
  * A `walletPicker` that selects with no UI, for tests and headless dev flows: the entry whose
@@ -23,9 +23,9 @@ const createAutoPicker = (pick) => async (entries) => {
23
23
  };
24
24
  //#endregion
25
25
  //#region src/testing/connectionInput.ts
26
- /** A `WalletSdk` method stand-in that returns a promise which never settles. */
26
+ /** A `DappSdkMethods` method stand-in that returns a promise which never settles. */
27
27
  const pending = () => new Promise(() => {});
28
- /** Every `WalletSdk` method left hanging, so a test only stubs the ones its path reaches. */
28
+ /** Every `DappSdkMethods` method left hanging, so a test only stubs the ones its path reaches. */
29
29
  const unstubbed = {
30
30
  connect: pending,
31
31
  disconnect: pending,
@@ -43,7 +43,7 @@ const unstubbed = {
43
43
  status: pending
44
44
  };
45
45
  /**
46
- * Machine input for a test actor, over a double satisfying the `WalletSdk` the machine types.
46
+ * Machine input for a test actor, over a double satisfying the `DappSdkMethods` the machine types.
47
47
  * Whatever the double leaves out never settles, and every `createSdk()` hands back a fresh object,
48
48
  * as `new DappSDK` does — so a retirement changes `context.sdk` here too.
49
49
  *
@@ -57,7 +57,6 @@ const connectionInput = (sdk = {}, overrides = {}) => ({
57
57
  }),
58
58
  initOptions: {},
59
59
  guardPicker: false,
60
- networkId: "canton:local",
61
60
  ...overrides
62
61
  });
63
62
  //#endregion
@@ -77,7 +76,7 @@ const toStateValue = ({ isLocked, readingAccounts, status }) => {
77
76
  return { session: { authenticated: readingAccounts ? "reading" : "ready" } };
78
77
  };
79
78
  /** Starts a real `connectionMachine` actor rehydrated at the given `SessionShape`. */
80
- const startSession = (shape, party, connectError, sdk) => {
79
+ const startSession = (shape, account, connectError, sdk) => {
81
80
  const input = connectionInput({}, { createSdk: () => sdk });
82
81
  const snapshot = connectionMachine.resolveState({
83
82
  value: toStateValue(shape),
@@ -85,7 +84,7 @@ const startSession = (shape, party, connectError, sdk) => {
85
84
  ...input,
86
85
  sdk,
87
86
  lastConnectError: connectError,
88
- party: shape.status === "connected" ? party : void 0
87
+ account: shape.status === "connected" ? account : void 0
89
88
  }
90
89
  });
91
90
  return createActor(connectionMachine, {
@@ -103,23 +102,23 @@ const startSession = (shape, party, connectError, sdk) => {
103
102
  *
104
103
  * @example
105
104
  * render(
106
- * <FakeSessionProvider status="connected" party={party}>
105
+ * <FakeSessionProvider status="connected" account={account}>
107
106
  * <ConnectButton />
108
107
  * </FakeSessionProvider>,
109
108
  * )
110
109
  *
111
110
  * @category Components
112
111
  */
113
- const FakeSessionProvider = ({ children, connectError, isLocked = false, party, readingAccounts = false, sdk = NO_SDK, status: initialStatus = "disconnected" }) => {
112
+ const FakeSessionProvider = ({ account, children, connectError, isLocked = false, readingAccounts = false, sdk = NO_SDK, status: initialStatus = "disconnected" }) => {
114
113
  const [status, setStatus] = useState(initialStatus);
115
114
  const connection = useMemo(() => startSession({
116
115
  isLocked,
117
116
  readingAccounts,
118
117
  status
119
- }, party, connectError, refusingSdk(sdk)), [
118
+ }, account, connectError, refusingSdk(sdk)), [
119
+ account,
120
120
  connectError,
121
121
  isLocked,
122
- party,
123
122
  readingAccounts,
124
123
  sdk,
125
124
  status
@@ -1,4 +1,4 @@
1
- import { DappSDK, ProviderAdapter, StatusEvent, TxChangedEvent, WalletPickerFn } from "@canton-network/dapp-sdk";
1
+ import { DappSDK, ProviderAdapter, StatusEvent, TxChangedEvent, Wallet, WalletPickerFn } from "@canton-network/dapp-sdk";
2
2
  import { ActorRefFrom } from "xstate";
3
3
  //#region src/machine/connectionActors.d.ts
4
4
  /**
@@ -36,17 +36,10 @@ type WalletEventsInput = {
36
36
  sdk: Pick<DappSDK, 'onStatusChanged' | 'removeOnStatusChanged'>;
37
37
  };
38
38
  //#endregion
39
- //#region src/machine/accountsMachine.d.ts
40
- /** The result of an account read, initial or pushed: the party found, or none. */
41
- type WalletAccounts = {
42
- party: Party | undefined;
43
- };
44
- //#endregion
45
39
  //#region src/machine/accountsActors.d.ts
46
- /** Input shared by `readAccounts` and `accountsEvents`: the sdk slice plus the network id. */
40
+ /** Input shared by `readPrimaryAccount` and `accountsEvents`: the sdk slice they call. */
47
41
  type AccountsInput = {
48
42
  sdk: Pick<DappSDK, 'listAccounts' | 'onAccountsChanged' | 'removeOnAccountsChanged'>;
49
- networkId: string;
50
43
  };
51
44
  //#endregion
52
45
  //#region src/machine/connectionMachine.d.ts
@@ -62,22 +55,21 @@ type WalletStatusUpdate = Pick<StatusEvent, 'connection'>;
62
55
  * import { connectionMachine } from '#src/machine/connectionMachine'
63
56
  *
64
57
  * const createSdk = () => new DappSDK({})
65
- * const input = { createSdk, initOptions: {}, guardPicker: true, networkId: 'canton:local' }
58
+ * const input = { createSdk, initOptions: {}, guardPicker: true }
66
59
  * createActor(connectionMachine, { input })
67
60
  *
68
61
  * @category Types
69
62
  */
70
63
  type ConnectionInput = {
71
- createSdk: () => WalletSdk;
64
+ createSdk: () => DappSdkMethods;
72
65
  initOptions: InitOptions;
73
66
  guardPicker: boolean;
74
- networkId: string;
75
67
  };
76
- /** What the machine carries beyond its input: the sdk it drives, the last failure, the party. */
68
+ /** What the machine carries beyond its input: the sdk it drives, the last failure, the account. */
77
69
  type ConnectionContext = ConnectionInput & {
78
- sdk: WalletSdk;
70
+ sdk: DappSdkMethods;
79
71
  lastConnectError: unknown;
80
- party: Party | undefined;
72
+ account: Account | undefined;
81
73
  };
82
74
  /**
83
75
  * The lifecycle itself: what a connect, a restore, a lock and a disconnect mean, and the tags the
@@ -101,25 +93,26 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
101
93
  status: WalletStatusUpdate;
102
94
  }, {
103
95
  [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<WalletStatusUpdate, ConnectInput, import("xstate").EventObject> | import("xstate").PromiseActorLogic<null, DisconnectInput, import("xstate").EventObject> | import("xstate").PromiseActorLogic<void, InitInput, import("xstate").EventObject> | import("xstate").PromiseActorLogic<WalletStatusUpdate, RestoreInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, WalletEventsInput, import("xstate").EventObject>> | undefined;
104
- accounts?: import("xstate").ActorRefFromLogic<import("xstate").StateMachine<AccountsInput & WalletAccounts & {
96
+ accounts?: import("xstate").ActorRefFromLogic<import("xstate").StateMachine<AccountsInput & {
97
+ account: Account | undefined;
105
98
  error: unknown;
106
99
  }, {
107
100
  type: "accounts.changed";
108
- accounts: WalletAccounts;
101
+ account: Account | undefined;
109
102
  }, {
110
- [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<WalletAccounts, AccountsInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>> | undefined;
103
+ [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>> | undefined;
111
104
  }, {
112
- src: "readAccounts";
113
- logic: import("xstate").PromiseActorLogic<WalletAccounts, AccountsInput, import("xstate").EventObject>;
105
+ src: "readPrimaryAccount";
106
+ logic: import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject>;
114
107
  id: string | undefined;
115
108
  } | {
116
109
  src: "accountsEvents";
117
110
  logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>;
118
111
  id: string | undefined;
119
112
  }, {
120
- type: "applyAccounts";
113
+ type: "applyAccount";
121
114
  params: {
122
- accounts: WalletAccounts;
115
+ account: Account | undefined;
123
116
  };
124
117
  } | {
125
118
  type: "assignError";
@@ -133,7 +126,7 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
133
126
  readonly ready: {};
134
127
  readonly unavailable: {};
135
128
  };
136
- }>> | undefined;
129
+ }, import("xstate").MetaObject>> | undefined;
137
130
  }, {
138
131
  src: "init";
139
132
  logic: import("xstate").PromiseActorLogic<void, InitInput, import("xstate").EventObject>;
@@ -156,25 +149,26 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
156
149
  id: string | undefined;
157
150
  } | {
158
151
  src: "accounts";
159
- logic: import("xstate").StateMachine<AccountsInput & WalletAccounts & {
152
+ logic: import("xstate").StateMachine<AccountsInput & {
153
+ account: Account | undefined;
160
154
  error: unknown;
161
155
  }, {
162
156
  type: "accounts.changed";
163
- accounts: WalletAccounts;
157
+ account: Account | undefined;
164
158
  }, {
165
- [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<WalletAccounts, AccountsInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>> | undefined;
159
+ [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject> | import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>> | undefined;
166
160
  }, {
167
- src: "readAccounts";
168
- logic: import("xstate").PromiseActorLogic<WalletAccounts, AccountsInput, import("xstate").EventObject>;
161
+ src: "readPrimaryAccount";
162
+ logic: import("xstate").PromiseActorLogic<import("@canton-network/dapp-sdk").Wallet | undefined, AccountsInput, import("xstate").EventObject>;
169
163
  id: string | undefined;
170
164
  } | {
171
165
  src: "accountsEvents";
172
166
  logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>;
173
167
  id: string | undefined;
174
168
  }, {
175
- type: "applyAccounts";
169
+ type: "applyAccount";
176
170
  params: {
177
- accounts: WalletAccounts;
171
+ account: Account | undefined;
178
172
  };
179
173
  } | {
180
174
  type: "assignError";
@@ -188,7 +182,7 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
188
182
  readonly ready: {};
189
183
  readonly unavailable: {};
190
184
  };
191
- }>;
185
+ }, import("xstate").MetaObject>;
192
186
  id: "accounts";
193
187
  }, {
194
188
  type: "assignError";
@@ -270,7 +264,7 @@ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext
270
264
  readonly initializing: {};
271
265
  readonly disconnecting: {};
272
266
  };
273
- }>;
267
+ }, import("xstate").MetaObject>;
274
268
  /**
275
269
  * The running connection machine. Consumers reach it narrowed to {@link ConnectionSubscription},
276
270
  * so `send` stays inside this package.
@@ -286,14 +280,14 @@ type ConnectionActorRef = ActorRefFrom<typeof connectionMachine>;
286
280
  *
287
281
  * @category Types
288
282
  */
289
- type WalletSdk = Pick<DappSDK, 'init' | 'connect' | 'disconnect' | 'status' | 'listAccounts' | 'onStatusChanged' | 'removeOnStatusChanged' | 'onAccountsChanged' | 'removeOnAccountsChanged' | 'onTxChanged' | 'removeOnTxChanged' | 'ledgerApi' | 'signMessage' | 'prepareExecuteAndWait'>;
283
+ type DappSdkMethods = Pick<DappSDK, 'init' | 'connect' | 'disconnect' | 'status' | 'listAccounts' | 'onStatusChanged' | 'removeOnStatusChanged' | 'onAccountsChanged' | 'removeOnAccountsChanged' | 'onTxChanged' | 'removeOnTxChanged' | 'ledgerApi' | 'signMessage' | 'prepareExecuteAndWait'>;
290
284
  /**
291
285
  * `'idle'` is "not determined yet", not "disconnected": gate a connect button on `'disconnected'`,
292
286
  * or a returning user is turned away before the boot restore runs. `'disconnecting'` is the session
293
287
  * tearing down; keep connect disabled until it settles, so a new connect never overlaps it.
294
288
  *
295
289
  * @example
296
- * const { status } = useParty()
290
+ * const { status } = useAccount()
297
291
  * if (status === 'idle') return null
298
292
  * return status === 'disconnected' ? <ConnectButton /> : <App />
299
293
  *
@@ -307,21 +301,30 @@ type ConnectionStatus = 'idle' | 'connecting' | 'connected' | 'disconnecting' |
307
301
  * @category Types
308
302
  */
309
303
  type PartyType = 'local' | 'external';
304
+ type PinnedAccount = {
305
+ primary: boolean;
306
+ partyId: string;
307
+ status: 'initialized' | 'allocated' | 'removed';
308
+ hint: string;
309
+ publicKey: string;
310
+ namespace: string;
311
+ networkId: string;
312
+ signingProviderId: string;
313
+ externalTxId?: string;
314
+ topologyTransactions?: string;
315
+ disabled?: boolean;
316
+ reason?: string;
317
+ };
318
+ type Exact<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
319
+ type Assert<T extends true> = T;
320
+ type AccountPinned = Assert<Exact<Wallet, PinnedAccount>>;
310
321
  /**
311
- * The connected account, normalized from the wallet's CIP-0103 account entry. `networkId` falls
312
- * back to `CantonConnectConfig.networkId` where the wallet reports none. `namespace` and
313
- * `signingProviderId` come through as reported; CIP-0103 names no `signingProviderId` values.
322
+ * One account the connected wallet reports: a party plus its key, signing provider and network.
323
+ * `dapp-sdk` calls this type `Wallet`; CIP-0103's own text says account.
314
324
  *
315
325
  * @category Types
316
326
  */
317
- interface Party {
318
- partyId: string;
319
- networkId: string;
320
- namespace: string;
321
- signingProviderId: string;
322
- name?: string;
323
- publicKey?: string;
324
- }
327
+ type Account = AccountPinned extends true ? Wallet : never;
325
328
  /**
326
329
  * Wiring for `CantonConnectProvider`. From `appName` alone a local dev app works: `canton:local` as
327
330
  * the network id and the WalletConnect chain id, `appName` as the description, the page origin as
@@ -376,7 +379,7 @@ interface TxStatusSnapshot {
376
379
  * @example
377
380
  * import type { ConnectionSubscription } from '#src/types'
378
381
  *
379
- * const partyOf = (connection: ConnectionSubscription) => connection.getSnapshot().context.party
382
+ * const accountOf = (connection: ConnectionSubscription) => connection.getSnapshot().context.account
380
383
  *
381
384
  * @category Types
382
385
  */
@@ -397,4 +400,4 @@ interface CantonConnectContextValue {
397
400
  resetConnectError: () => void;
398
401
  }
399
402
  //#endregion
400
- export { Party as a, WalletSdk as c, ConnectionSubscription as i, ConnectionInput as l, CantonConnectContextValue as n, PartyType as o, ConnectionStatus as r, TxStatusSnapshot as s, CantonConnectConfig as t, InitOptions as u };
403
+ export { ConnectionSubscription as a, TxStatusSnapshot as c, ConnectionStatus as i, ConnectionInput as l, CantonConnectConfig as n, DappSdkMethods as o, CantonConnectContextValue as r, PartyType as s, Account as t, InitOptions as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bootnodedev/canton-connect",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "wagmi-style React hooks for connecting Canton dApps to CIP-0103 wallets",
5
5
  "repository": {
6
6
  "type": "git",