@bootnodedev/canton-connect 0.3.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.
@@ -0,0 +1,291 @@
1
+ import { i as connectionMachine, t as CantonConnectContext } from "../CantonConnectProvider-CJ1yWGXz.js";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { createActor } from "xstate";
4
+ import { CANTON_ANNOUNCE_PROVIDER_EVENT, CANTON_REQUEST_PROVIDER_EVENT, WalletEvent } from "@canton-network/core-types";
5
+ import { jsx } from "react/jsx-runtime";
6
+ //#region src/testing/autoPicker.ts
7
+ /**
8
+ * A `walletPicker` that selects with no UI, for tests and headless dev flows: the entry whose
9
+ * `providerId` matches `pick`, or the first discovered one.
10
+ *
11
+ * @throws when no discovered entry matches `pick`, so a test naming a wallet that never registered
12
+ * fails at the picker rather than at the connect.
13
+ *
14
+ * @example
15
+ * const config = { appName: 'Vesting', walletPicker: createAutoPicker('mock') }
16
+ *
17
+ * @category Utilities
18
+ */
19
+ const createAutoPicker = (pick) => async (entries) => {
20
+ const chosen = pick === void 0 ? entries[0] : entries.find((entry) => entry.providerId === pick);
21
+ if (chosen === void 0) throw new Error(`auto-picker: no wallet matching ${pick ?? "(first)"}`);
22
+ return chosen;
23
+ };
24
+ //#endregion
25
+ //#region src/testing/connectionInput.ts
26
+ /** A `WalletSdk` method stand-in that returns a promise which never settles. */
27
+ const pending = () => new Promise(() => {});
28
+ /** Every `WalletSdk` method left hanging, so a test only stubs the ones its path reaches. */
29
+ const unstubbed = {
30
+ connect: pending,
31
+ disconnect: pending,
32
+ init: pending,
33
+ ledgerApi: pending,
34
+ listAccounts: pending,
35
+ onAccountsChanged: pending,
36
+ onStatusChanged: pending,
37
+ onTxChanged: pending,
38
+ prepareExecuteAndWait: pending,
39
+ removeOnAccountsChanged: pending,
40
+ removeOnStatusChanged: pending,
41
+ removeOnTxChanged: pending,
42
+ signMessage: pending,
43
+ status: pending
44
+ };
45
+ /**
46
+ * Machine input for a test actor, over a double satisfying the `WalletSdk` the machine types.
47
+ * Whatever the double leaves out never settles, and every `createSdk()` hands back a fresh object,
48
+ * as `new DappSDK` does — so a retirement changes `context.sdk` here too.
49
+ *
50
+ * @example
51
+ * const actor = createActor(machine, { input: connectionInput(sdkDouble) })
52
+ */
53
+ const connectionInput = (sdk = {}, overrides = {}) => ({
54
+ createSdk: () => ({
55
+ ...unstubbed,
56
+ ...sdk
57
+ }),
58
+ initOptions: {},
59
+ guardPicker: false,
60
+ networkId: "canton:local",
61
+ ...overrides
62
+ });
63
+ //#endregion
64
+ //#region src/testing/fakeSession.tsx
65
+ const CONFIG = { appName: "fake-session" };
66
+ const NO_SDK = {};
67
+ /** A `sdk` wrapper that throws naming the method for anything the test never stubbed. */
68
+ const refusingSdk = (supplied) => new Proxy({}, { get: (_, key) => {
69
+ const method = supplied[key];
70
+ if (method === void 0) throw new Error(`fake session has no sdk.${String(key)} — drive the real provider for that`);
71
+ return method;
72
+ } });
73
+ /** Turns a `SessionShape` into the state value the real machine would hold for it. */
74
+ const toStateValue = ({ isLocked, readingAccounts, status }) => {
75
+ if (status !== "connected") return status;
76
+ if (isLocked) return { session: "unauthenticated" };
77
+ return { session: { authenticated: readingAccounts ? "reading" : "ready" } };
78
+ };
79
+ /** Starts a real `connectionMachine` actor rehydrated at the given `SessionShape`. */
80
+ const startSession = (shape, party, connectError, sdk) => {
81
+ const input = connectionInput({}, { createSdk: () => sdk });
82
+ const snapshot = connectionMachine.resolveState({
83
+ value: toStateValue(shape),
84
+ context: {
85
+ ...input,
86
+ sdk,
87
+ lastConnectError: connectError,
88
+ party: shape.status === "connected" ? party : void 0
89
+ }
90
+ });
91
+ return createActor(connectionMachine, {
92
+ input,
93
+ snapshot
94
+ }).start();
95
+ };
96
+ /**
97
+ * Stands in for `CantonConnectProvider` with the session already in a given shape, so a component
98
+ * test asserts on markup without paying the SDK's discovery sleeps or its connect flow. The shape
99
+ * is a real `connectionMachine` actor rehydrated at the state the props ask for, so the hooks
100
+ * select from it exactly as they do in the app. `connect` and `disconnect` move the session, but
101
+ * reach for the real provider plus `createMockAdapter` to test connecting itself — the intermediate
102
+ * states here are not the SDK's.
103
+ *
104
+ * @example
105
+ * render(
106
+ * <FakeSessionProvider status="connected" party={party}>
107
+ * <ConnectButton />
108
+ * </FakeSessionProvider>,
109
+ * )
110
+ *
111
+ * @category Components
112
+ */
113
+ const FakeSessionProvider = ({ children, connectError, isLocked = false, party, readingAccounts = false, sdk = NO_SDK, status: initialStatus = "disconnected" }) => {
114
+ const [status, setStatus] = useState(initialStatus);
115
+ const connection = useMemo(() => startSession({
116
+ isLocked,
117
+ readingAccounts,
118
+ status
119
+ }, party, connectError, refusingSdk(sdk)), [
120
+ connectError,
121
+ isLocked,
122
+ party,
123
+ readingAccounts,
124
+ sdk,
125
+ status
126
+ ]);
127
+ useEffect(() => () => connection.stop(), [connection]);
128
+ const connect = useCallback(async () => {
129
+ setStatus("connected");
130
+ }, []);
131
+ const disconnect = useCallback(async () => {
132
+ setStatus("disconnected");
133
+ }, []);
134
+ const value = useMemo(() => ({
135
+ config: CONFIG,
136
+ connection,
137
+ connect,
138
+ cancelConnect: () => connection.send({ type: "connect.cancel" }),
139
+ disconnect,
140
+ resetConnectError: () => connection.send({ type: "connectError.reset" })
141
+ }), [
142
+ connection,
143
+ connect,
144
+ disconnect
145
+ ]);
146
+ return /* @__PURE__ */ jsx(CantonConnectContext.Provider, {
147
+ value,
148
+ children
149
+ });
150
+ };
151
+ //#endregion
152
+ //#region src/testing/fakeWallet.ts
153
+ const JSON_RPC_METHOD_NOT_FOUND = -32601;
154
+ const FAKE_PUBLIC_KEY = "fake-public-key";
155
+ const FAKE_SIGNING_PROVIDER_ID = "fake";
156
+ const FAKE_NETWORK_ID = "canton:local";
157
+ const FAKE_WALLET_STATUS = "allocated";
158
+ /** Shapes one `FakeWalletAccount` into the `Wallet` object `listAccounts` reports. */
159
+ const toWallet = (account) => ({
160
+ primary: account.primary === true,
161
+ partyId: account.partyId,
162
+ status: FAKE_WALLET_STATUS,
163
+ hint: account.name ?? account.partyId,
164
+ publicKey: account.publicKey ?? FAKE_PUBLIC_KEY,
165
+ namespace: account.partyId.split("::")[1] ?? account.partyId,
166
+ networkId: account.networkId ?? FAKE_NETWORK_ID,
167
+ signingProviderId: FAKE_SIGNING_PROVIDER_ID
168
+ });
169
+ /**
170
+ * A fake CIP-0103 extension wallet for tests. It speaks the real postMessage protocol, so it
171
+ * exercises the SDK's genuine `ExtensionAdapter` rather than a stub. Answers `connect`, `status`,
172
+ * `listAccounts` and `disconnect`; anything else rejects naming the method. Reach for
173
+ * `createMockAdapter` instead where the transport is not what is under test.
174
+ *
175
+ * @example
176
+ * const wallet = createFakeWallet({ id: 'mock' })
177
+ * wallet.push('statusChanged', { connection: { isConnected: false } })
178
+ * wallet.dispose()
179
+ *
180
+ * @category Utilities
181
+ */
182
+ const createFakeWallet = (options) => {
183
+ const target = options.target ?? options.id;
184
+ const accounts = options.accounts ?? [{
185
+ partyId: `${options.id}::1220abcd`,
186
+ primary: true
187
+ }];
188
+ let statusCallCount = 0;
189
+ const announce = () => {
190
+ window.dispatchEvent(new CustomEvent(CANTON_ANNOUNCE_PROVIDER_EVENT, { detail: {
191
+ id: options.id,
192
+ name: options.name ?? options.id,
193
+ target
194
+ } }));
195
+ };
196
+ const nextStatusIsConnected = () => {
197
+ const responses = options.statusResponses;
198
+ if (responses === void 0 || responses.length === 0) return true;
199
+ const index = Math.min(statusCallCount, responses.length - 1);
200
+ statusCallCount += 1;
201
+ return responses[index];
202
+ };
203
+ const buildStatus = () => ({
204
+ provider: {
205
+ id: options.id,
206
+ providerType: "browser"
207
+ },
208
+ connection: {
209
+ isConnected: nextStatusIsConnected(),
210
+ isNetworkConnected: true
211
+ }
212
+ });
213
+ const buildConnect = () => ({
214
+ isConnected: true,
215
+ isNetworkConnected: true
216
+ });
217
+ const responses = {
218
+ status: buildStatus,
219
+ connect: buildConnect,
220
+ listAccounts: () => accounts.map(toWallet),
221
+ disconnect: () => ({})
222
+ };
223
+ const answer = (method) => {
224
+ const handler = responses[method];
225
+ if (handler === void 0) return { error: {
226
+ code: JSON_RPC_METHOD_NOT_FOUND,
227
+ message: `createFakeWallet does not implement "${method}"`
228
+ } };
229
+ return { result: handler() };
230
+ };
231
+ const onMessage = (event) => {
232
+ const data = event.data;
233
+ if (data?.type === void 0) return;
234
+ if (data.target !== void 0 && data.target !== target) return;
235
+ if (data.type === WalletEvent.SPLICE_WALLET_EXT_READY) {
236
+ window.postMessage({
237
+ type: WalletEvent.SPLICE_WALLET_EXT_ACK,
238
+ target
239
+ }, "*");
240
+ return;
241
+ }
242
+ const requestId = data.request?.id;
243
+ if (!(data.type === WalletEvent.SPLICE_WALLET_REQUEST && requestId !== void 0 && requestId !== null)) return;
244
+ const method = data.request?.method ?? "";
245
+ window.postMessage({
246
+ type: WalletEvent.SPLICE_WALLET_RESPONSE,
247
+ response: {
248
+ jsonrpc: "2.0",
249
+ id: requestId,
250
+ ...answer(method)
251
+ }
252
+ }, "*");
253
+ };
254
+ const push = (method, params) => {
255
+ window.postMessage({
256
+ type: WalletEvent.SPLICE_WALLET_REQUEST,
257
+ request: {
258
+ jsonrpc: "2.0",
259
+ method,
260
+ params
261
+ },
262
+ target
263
+ }, "*");
264
+ };
265
+ window.addEventListener("message", onMessage);
266
+ window.addEventListener(CANTON_REQUEST_PROVIDER_EVENT, announce);
267
+ queueMicrotask(announce);
268
+ return {
269
+ announce,
270
+ push,
271
+ dispose: () => {
272
+ window.removeEventListener("message", onMessage);
273
+ window.removeEventListener(CANTON_REQUEST_PROVIDER_EVENT, announce);
274
+ }
275
+ };
276
+ };
277
+ //#endregion
278
+ //#region src/testing/pause.ts
279
+ /**
280
+ * Real-timer sleep, which is how a suite awaits a promise-settling send; `pause(0)` flushes the
281
+ * pending macrotasks. Reach for it over `waitFor`, whose retry window turns a genuine red into a
282
+ * timeout rather than a failed assertion.
283
+ *
284
+ * @example
285
+ * await pause(0) // one macrotask on, so the send above has settled
286
+ *
287
+ * @category Utilities
288
+ */
289
+ const pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
290
+ //#endregion
291
+ export { FakeSessionProvider, createAutoPicker, createFakeWallet, pause };
@@ -0,0 +1,385 @@
1
+ import { DappSDK, ProviderAdapter, StatusEvent, TxChangedEvent, WalletPickerFn } from "@canton-network/dapp-sdk";
2
+ import { ActorRefFrom } from "xstate";
3
+ //#region src/machine/connectionActors.d.ts
4
+ /**
5
+ * What `DappSDK.init` accepts, read off the SDK rather than restated. The init actor defaults
6
+ * `defaultAdapters` to empty, dropping the SDK's bundled dev gateway, and whatever is set here
7
+ * wins over that default.
8
+ *
9
+ * @example
10
+ * const initOptions: InitOptions = { additionalAdapters: [createMockAdapter()] }
11
+ *
12
+ * @category Types
13
+ */
14
+ type InitOptions = NonNullable<Parameters<DappSDK['init']>[0]>;
15
+ /** Input for the `init` actor: the sdk slice and options `ensureInit` needs to boot it. */
16
+ type InitInput = {
17
+ sdk: Pick<DappSDK, 'init'>;
18
+ initOptions: InitOptions;
19
+ };
20
+ /** Input for the `connect` actor: enough sdk to init, connect, and recover a session. */
21
+ type ConnectInput = {
22
+ sdk: Pick<DappSDK, 'connect' | 'init' | 'status'>;
23
+ initOptions: InitOptions;
24
+ guardPicker: boolean;
25
+ };
26
+ /** Input for the `restore` actor: just enough sdk to read the wallet's status. */
27
+ type RestoreInput = {
28
+ sdk: Pick<DappSDK, 'status'>;
29
+ };
30
+ /** Input for the `disconnect` actor: the sdk slice it calls to end the session. */
31
+ type DisconnectInput = {
32
+ sdk: Pick<DappSDK, 'disconnect'>;
33
+ };
34
+ /** Input for the `walletEvents` actor: the sdk slice it subscribes to and unsubscribes from. */
35
+ type WalletEventsInput = {
36
+ sdk: Pick<DappSDK, 'onStatusChanged' | 'removeOnStatusChanged'>;
37
+ };
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
+ //#region src/machine/accountsActors.d.ts
46
+ /** Input shared by `readAccounts` and `accountsEvents`: the sdk slice plus the network id. */
47
+ type AccountsInput = {
48
+ sdk: Pick<DappSDK, 'listAccounts' | 'onAccountsChanged' | 'removeOnAccountsChanged'>;
49
+ networkId: string;
50
+ };
51
+ //#endregion
52
+ //#region src/machine/connectionMachine.d.ts
53
+ /** The wallet's connection status, narrowed from the SDK's `StatusEvent`. */
54
+ type WalletStatusUpdate = Pick<StatusEvent, 'connection'>;
55
+ /**
56
+ * What the machine needs to build and drive its own `DappSDK`. Read once, at actor creation: as in
57
+ * wagmi, a config swapped afterwards reaches the hooks but not the connection lifecycle.
58
+ *
59
+ * @example
60
+ * import { DappSDK } from '@canton-network/dapp-sdk'
61
+ * import { createActor } from 'xstate'
62
+ * import { connectionMachine } from '#src/machine/connectionMachine'
63
+ *
64
+ * const createSdk = () => new DappSDK({})
65
+ * const input = { createSdk, initOptions: {}, guardPicker: true, networkId: 'canton:local' }
66
+ * createActor(connectionMachine, { input })
67
+ *
68
+ * @category Types
69
+ */
70
+ type ConnectionInput = {
71
+ createSdk: () => WalletSdk;
72
+ initOptions: InitOptions;
73
+ guardPicker: boolean;
74
+ networkId: string;
75
+ };
76
+ /** What the machine carries beyond its input: the sdk it drives, the last failure, the party. */
77
+ type ConnectionContext = ConnectionInput & {
78
+ sdk: WalletSdk;
79
+ lastConnectError: unknown;
80
+ party: Party | undefined;
81
+ };
82
+ /**
83
+ * The lifecycle itself: what a connect, a restore, a lock and a disconnect mean, and the tags the
84
+ * bridges and hooks read off them. `CantonConnectProvider` runs it; reach for it directly only to
85
+ * drive a session in a test.
86
+ *
87
+ * @category Types
88
+ */
89
+ declare const connectionMachine: import("xstate").StateMachine<ConnectionContext, {
90
+ type: "connect";
91
+ } | {
92
+ type: "connect.cancel";
93
+ } | {
94
+ type: "connectError.reset";
95
+ } | {
96
+ type: "disconnect";
97
+ } | {
98
+ type: "restore";
99
+ } | {
100
+ type: "wallet.statusChanged";
101
+ status: WalletStatusUpdate;
102
+ }, {
103
+ [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 & {
105
+ error: unknown;
106
+ }, {
107
+ type: "accounts.changed";
108
+ accounts: WalletAccounts;
109
+ }, {
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;
111
+ }, {
112
+ src: "readAccounts";
113
+ logic: import("xstate").PromiseActorLogic<WalletAccounts, AccountsInput, import("xstate").EventObject>;
114
+ id: string | undefined;
115
+ } | {
116
+ src: "accountsEvents";
117
+ logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>;
118
+ id: string | undefined;
119
+ }, {
120
+ type: "applyAccounts";
121
+ params: {
122
+ accounts: WalletAccounts;
123
+ };
124
+ } | {
125
+ type: "assignError";
126
+ params: {
127
+ error: unknown;
128
+ };
129
+ }, never, never, "reading" | "ready" | "unavailable", string, AccountsInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
130
+ id: "accounts";
131
+ states: {
132
+ readonly reading: {};
133
+ readonly ready: {};
134
+ readonly unavailable: {};
135
+ };
136
+ }>> | undefined;
137
+ }, {
138
+ src: "init";
139
+ logic: import("xstate").PromiseActorLogic<void, InitInput, import("xstate").EventObject>;
140
+ id: string | undefined;
141
+ } | {
142
+ src: "connect";
143
+ logic: import("xstate").PromiseActorLogic<WalletStatusUpdate, ConnectInput, import("xstate").EventObject>;
144
+ id: string | undefined;
145
+ } | {
146
+ src: "disconnect";
147
+ logic: import("xstate").PromiseActorLogic<null, DisconnectInput, import("xstate").EventObject>;
148
+ id: string | undefined;
149
+ } | {
150
+ src: "restore";
151
+ logic: import("xstate").PromiseActorLogic<WalletStatusUpdate, RestoreInput, import("xstate").EventObject>;
152
+ id: string | undefined;
153
+ } | {
154
+ src: "walletEvents";
155
+ logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, WalletEventsInput, import("xstate").EventObject>;
156
+ id: string | undefined;
157
+ } | {
158
+ src: "accounts";
159
+ logic: import("xstate").StateMachine<AccountsInput & WalletAccounts & {
160
+ error: unknown;
161
+ }, {
162
+ type: "accounts.changed";
163
+ accounts: WalletAccounts;
164
+ }, {
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;
166
+ }, {
167
+ src: "readAccounts";
168
+ logic: import("xstate").PromiseActorLogic<WalletAccounts, AccountsInput, import("xstate").EventObject>;
169
+ id: string | undefined;
170
+ } | {
171
+ src: "accountsEvents";
172
+ logic: import("xstate").CallbackActorLogic<import("xstate").EventObject, AccountsInput, import("xstate").EventObject>;
173
+ id: string | undefined;
174
+ }, {
175
+ type: "applyAccounts";
176
+ params: {
177
+ accounts: WalletAccounts;
178
+ };
179
+ } | {
180
+ type: "assignError";
181
+ params: {
182
+ error: unknown;
183
+ };
184
+ }, never, never, "reading" | "ready" | "unavailable", string, AccountsInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
185
+ id: "accounts";
186
+ states: {
187
+ readonly reading: {};
188
+ readonly ready: {};
189
+ readonly unavailable: {};
190
+ };
191
+ }>;
192
+ id: "accounts";
193
+ }, {
194
+ type: "assignError";
195
+ params: {
196
+ error: unknown;
197
+ };
198
+ } | {
199
+ type: "assignDeclined";
200
+ params: {
201
+ connection: WalletStatusUpdate["connection"];
202
+ };
203
+ } | {
204
+ type: "forgetError";
205
+ params: import("xstate").NonReducibleUnknown;
206
+ } | {
207
+ type: "retireSdk";
208
+ params: import("xstate").NonReducibleUnknown;
209
+ }, {
210
+ type: "isAuthenticated";
211
+ params: {
212
+ connection: WalletStatusUpdate["connection"] | undefined;
213
+ };
214
+ } | {
215
+ type: "isPickerClosed";
216
+ params: {
217
+ error: unknown;
218
+ };
219
+ } | {
220
+ type: "isInitFailed";
221
+ params: {
222
+ error: unknown;
223
+ };
224
+ }, "disconnectTimeout", "idle" | "disconnecting" | "disconnected" | "initializing" | "failure" | {
225
+ connecting: "new" | "changing";
226
+ } | {
227
+ session: "unauthenticated" | {
228
+ authenticated: "reading" | "ready" | "unavailable";
229
+ };
230
+ } | {
231
+ retiring: "new" | "changing";
232
+ } | {
233
+ restoring: "new" | "changing";
234
+ }, "connecting" | "connect.settled" | "connect.failed" | "connect.cancelled" | "unauthenticated" | "disconnect.settled", ConnectionInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
235
+ id: "connection";
236
+ states: {
237
+ readonly idle: {};
238
+ readonly disconnected: {};
239
+ readonly connecting: {
240
+ states: {
241
+ readonly new: {};
242
+ readonly changing: {};
243
+ };
244
+ };
245
+ readonly session: {
246
+ states: {
247
+ readonly authenticated: {
248
+ states: {
249
+ readonly reading: {};
250
+ readonly ready: {};
251
+ readonly unavailable: {};
252
+ };
253
+ };
254
+ readonly unauthenticated: {};
255
+ };
256
+ };
257
+ readonly failure: {};
258
+ readonly retiring: {
259
+ states: {
260
+ readonly new: {};
261
+ readonly changing: {};
262
+ };
263
+ };
264
+ readonly restoring: {
265
+ states: {
266
+ readonly new: {};
267
+ readonly changing: {};
268
+ };
269
+ };
270
+ readonly initializing: {};
271
+ readonly disconnecting: {};
272
+ };
273
+ }>;
274
+ /**
275
+ * The running connection machine. Consumers reach it narrowed to {@link ConnectionSubscription},
276
+ * so `send` stays inside this package.
277
+ *
278
+ * @category Types
279
+ */
280
+ type ConnectionActorRef = ActorRefFrom<typeof connectionMachine>;
281
+ //#endregion
282
+ //#region src/types.d.ts
283
+ /**
284
+ * The slice of `DappSDK` this package calls. Deliberately narrower than the class: it states
285
+ * which methods the wrapper supports, and a real `DappSDK` satisfies it structurally.
286
+ *
287
+ * @category Types
288
+ */
289
+ type WalletSdk = Pick<DappSDK, 'init' | 'connect' | 'disconnect' | 'status' | 'listAccounts' | 'onStatusChanged' | 'removeOnStatusChanged' | 'onAccountsChanged' | 'removeOnAccountsChanged' | 'onTxChanged' | 'removeOnTxChanged' | 'ledgerApi' | 'signMessage' | 'prepareExecuteAndWait'>;
290
+ /**
291
+ * `'idle'` is "not determined yet", not "disconnected": gate a connect button on `'disconnected'`,
292
+ * or a returning user is turned away before the boot restore runs. `'disconnecting'` is the session
293
+ * tearing down; keep connect disabled until it settles, so a new connect never overlaps it.
294
+ *
295
+ * @example
296
+ * const { status } = useParty()
297
+ * if (status === 'idle') return null
298
+ * return status === 'disconnected' ? <ConnectButton /> : <App />
299
+ *
300
+ * @category Types
301
+ */
302
+ type ConnectionStatus = 'idle' | 'connecting' | 'connected' | 'disconnecting' | 'disconnected';
303
+ /**
304
+ * Canton's terms: a local party lives under the hosting participant's namespace and the participant
305
+ * signs for it; an external party lives under its own key's and signs for itself.
306
+ *
307
+ * @category Types
308
+ */
309
+ type PartyType = 'local' | 'external';
310
+ /**
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.
314
+ *
315
+ * @category Types
316
+ */
317
+ interface Party {
318
+ partyId: string;
319
+ networkId: string;
320
+ namespace: string;
321
+ signingProviderId: string;
322
+ name?: string;
323
+ publicKey?: string;
324
+ }
325
+ /**
326
+ * Wiring for `CantonConnectProvider`. From `appName` alone a local dev app works: `canton:local` as
327
+ * the network id and the WalletConnect chain id, `appName` as the description, the page origin as
328
+ * the url, and the SDK's popup as the picker, guarded so closing it rejects — pass a `walletPicker`
329
+ * and that surface is yours. The app fields stay inert until `walletConnectProjectId` (Reown) is set.
330
+ *
331
+ * @example
332
+ * const config: CantonConnectConfig = { appName: 'Vesting', networkId: 'canton:devnet' }
333
+ *
334
+ * @category Configuration
335
+ */
336
+ interface CantonConnectConfig {
337
+ appName: string;
338
+ appDescription?: string;
339
+ appUrl?: string;
340
+ networkId?: string;
341
+ walletConnectProjectId?: string;
342
+ walletPicker?: WalletPickerFn;
343
+ additionalAdapters?: ProviderAdapter[];
344
+ }
345
+ /**
346
+ * Mirrored from the SDK's `txChanged` event as a command moves through
347
+ * pending, signed, executed or failed.
348
+ *
349
+ * @category Types
350
+ */
351
+ interface TxStatusSnapshot {
352
+ status: TxChangedEvent['status'];
353
+ commandId: TxChangedEvent['commandId'];
354
+ payload?: unknown;
355
+ }
356
+ /**
357
+ * The connection machine as `useSelector` sees it: subscribe and read, never send. Narrowed from
358
+ * the actor ref so `connect` and `disconnect` stay the only senders — a transition asked for
359
+ * anywhere else is a lifecycle rule living outside the machine.
360
+ *
361
+ * @example
362
+ * import type { ConnectionSubscription } from '#src/types'
363
+ *
364
+ * const partyOf = (connection: ConnectionSubscription) => connection.getSnapshot().context.party
365
+ *
366
+ * @category Types
367
+ */
368
+ type ConnectionSubscription = Pick<ConnectionActorRef, 'getSnapshot' | 'subscribe'>;
369
+ /**
370
+ * One connection and the actions on it, published once. Every hook selects its slice off
371
+ * `connection`: prefer the narrower hooks and reach for this only when none exposes the slice.
372
+ * The four actions are `useConnect`'s own, documented there.
373
+ *
374
+ * @category Types
375
+ */
376
+ interface CantonConnectContextValue {
377
+ config: CantonConnectConfig;
378
+ connection: ConnectionSubscription;
379
+ connect: () => Promise<void>;
380
+ cancelConnect: () => void;
381
+ disconnect: () => Promise<void>;
382
+ resetConnectError: () => void;
383
+ }
384
+ //#endregion
385
+ 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 };