@mysten-incubation/dev-wallet 0.2.0 → 0.4.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/CHANGELOG.md +167 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.127.0/helpers → _@oxc-project_runtime@0.135.0/helpers/esm}/decorate.mjs +1 -1
- package/dist/adapters/base-adapter.d.mts.map +1 -1
- package/dist/adapters/base-adapter.mjs.map +1 -1
- package/dist/adapters/build-managed-account.mjs.map +1 -1
- package/dist/adapters/devstack-adapter.d.mts.map +1 -1
- package/dist/adapters/devstack-adapter.mjs.map +1 -1
- package/dist/adapters/devstack-paths.d.mts +0 -1
- package/dist/adapters/devstack-paths.d.mts.map +1 -1
- package/dist/adapters/devstack-paths.mjs +1 -2
- package/dist/adapters/devstack-paths.mjs.map +1 -1
- package/dist/adapters/fork-relay.d.mts.map +1 -1
- package/dist/adapters/fork-relay.mjs.map +1 -1
- package/dist/adapters/idb-store.mjs.map +1 -1
- package/dist/adapters/in-memory-adapter.d.mts.map +1 -1
- package/dist/adapters/in-memory-adapter.mjs.map +1 -1
- package/dist/adapters/passkey-adapter.d.mts.map +1 -1
- package/dist/adapters/passkey-adapter.mjs.map +1 -1
- package/dist/adapters/remote-cli-adapter.d.mts.map +1 -1
- package/dist/adapters/remote-cli-adapter.mjs.map +1 -1
- package/dist/adapters/webcrypto-adapter.d.mts.map +1 -1
- package/dist/adapters/webcrypto-adapter.mjs.map +1 -1
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/client/dev-wallet-client.d.mts.map +1 -1
- package/dist/client/dev-wallet-client.mjs.map +1 -1
- package/dist/client/request-handler.d.mts.map +1 -1
- package/dist/client/request-handler.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/inject/index.d.mts +61 -0
- package/dist/inject/index.d.mts.map +1 -0
- package/dist/inject/index.mjs +61 -0
- package/dist/inject/index.mjs.map +1 -0
- package/dist/react/components.d.mts +6 -8
- package/dist/react/components.d.mts.map +1 -1
- package/dist/react/components.mjs.map +1 -1
- package/dist/react/context.d.mts +2 -3
- package/dist/react/context.d.mts.map +1 -1
- package/dist/react/context.mjs.map +1 -1
- package/dist/react/useDevWallet.d.mts +3 -11
- package/dist/react/useDevWallet.d.mts.map +1 -1
- package/dist/react/useDevWallet.mjs +14 -36
- package/dist/react/useDevWallet.mjs.map +1 -1
- package/dist/server/cli-signing-middleware.d.mts.map +1 -1
- package/dist/server/cli-signing-middleware.mjs.map +1 -1
- package/dist/standalone/assets/base-adapter-DET6CP7z.js +1 -0
- package/dist/standalone/assets/in-memory-adapter-CX7xym4e.js +1 -0
- package/dist/standalone/assets/main-CuOnBmaa.js +7 -0
- package/dist/standalone/assets/webcrypto-adapter-CUQmbHDy.js +1 -0
- package/dist/standalone/bookmarklet.js +5 -5
- package/dist/standalone/index.html +2 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/ui/copy-controller.mjs.map +1 -1
- package/dist/ui/dev-wallet-account-selector.d.mts +2 -3
- package/dist/ui/dev-wallet-account-selector.d.mts.map +1 -1
- package/dist/ui/dev-wallet-account-selector.mjs +1 -1
- package/dist/ui/dev-wallet-account-selector.mjs.map +1 -1
- package/dist/ui/dev-wallet-accounts.d.mts +2 -3
- package/dist/ui/dev-wallet-accounts.d.mts.map +1 -1
- package/dist/ui/dev-wallet-accounts.mjs +1 -1
- package/dist/ui/dev-wallet-accounts.mjs.map +1 -1
- package/dist/ui/dev-wallet-balances.d.mts +2 -3
- package/dist/ui/dev-wallet-balances.d.mts.map +1 -1
- package/dist/ui/dev-wallet-balances.mjs +1 -1
- package/dist/ui/dev-wallet-balances.mjs.map +1 -1
- package/dist/ui/dev-wallet-connect.d.mts +2 -3
- package/dist/ui/dev-wallet-connect.d.mts.map +1 -1
- package/dist/ui/dev-wallet-connect.mjs +1 -1
- package/dist/ui/dev-wallet-connect.mjs.map +1 -1
- package/dist/ui/dev-wallet-dropdown.d.mts +2 -3
- package/dist/ui/dev-wallet-dropdown.d.mts.map +1 -1
- package/dist/ui/dev-wallet-dropdown.mjs +1 -1
- package/dist/ui/dev-wallet-dropdown.mjs.map +1 -1
- package/dist/ui/dev-wallet-fork-panel.d.mts +2 -3
- package/dist/ui/dev-wallet-fork-panel.d.mts.map +1 -1
- package/dist/ui/dev-wallet-fork-panel.mjs +1 -1
- package/dist/ui/dev-wallet-fork-panel.mjs.map +1 -1
- package/dist/ui/dev-wallet-network-badge.d.mts +2 -3
- package/dist/ui/dev-wallet-network-badge.d.mts.map +1 -1
- package/dist/ui/dev-wallet-network-badge.mjs +1 -1
- package/dist/ui/dev-wallet-network-badge.mjs.map +1 -1
- package/dist/ui/dev-wallet-new-account.d.mts +2 -3
- package/dist/ui/dev-wallet-new-account.d.mts.map +1 -1
- package/dist/ui/dev-wallet-new-account.mjs +1 -1
- package/dist/ui/dev-wallet-new-account.mjs.map +1 -1
- package/dist/ui/dev-wallet-objects.d.mts +2 -3
- package/dist/ui/dev-wallet-objects.d.mts.map +1 -1
- package/dist/ui/dev-wallet-objects.mjs +1 -1
- package/dist/ui/dev-wallet-objects.mjs.map +1 -1
- package/dist/ui/dev-wallet-panel.d.mts +2 -3
- package/dist/ui/dev-wallet-panel.d.mts.map +1 -1
- package/dist/ui/dev-wallet-panel.mjs +1 -1
- package/dist/ui/dev-wallet-panel.mjs.map +1 -1
- package/dist/ui/dev-wallet-popup.d.mts +2 -3
- package/dist/ui/dev-wallet-popup.d.mts.map +1 -1
- package/dist/ui/dev-wallet-popup.mjs +1 -1
- package/dist/ui/dev-wallet-popup.mjs.map +1 -1
- package/dist/ui/dev-wallet-settings.d.mts +2 -3
- package/dist/ui/dev-wallet-settings.d.mts.map +1 -1
- package/dist/ui/dev-wallet-settings.mjs +1 -1
- package/dist/ui/dev-wallet-settings.mjs.map +1 -1
- package/dist/ui/dev-wallet-signing-modal.d.mts +2 -3
- package/dist/ui/dev-wallet-signing-modal.d.mts.map +1 -1
- package/dist/ui/dev-wallet-signing-modal.mjs +1 -1
- package/dist/ui/dev-wallet-signing-modal.mjs.map +1 -1
- package/dist/ui/dev-wallet-signing.d.mts +2 -3
- package/dist/ui/dev-wallet-signing.d.mts.map +1 -1
- package/dist/ui/dev-wallet-signing.mjs +2 -1
- package/dist/ui/dev-wallet-signing.mjs.map +1 -1
- package/dist/ui/dev-wallet-standalone.d.mts +2 -3
- package/dist/ui/dev-wallet-standalone.d.mts.map +1 -1
- package/dist/ui/dev-wallet-standalone.mjs +1 -1
- package/dist/ui/dev-wallet-standalone.mjs.map +1 -1
- package/dist/ui/dev-wallet-tab-bar.d.mts +1 -2
- package/dist/ui/dev-wallet-tab-bar.d.mts.map +1 -1
- package/dist/ui/dev-wallet-tab-bar.mjs +1 -1
- package/dist/ui/dev-wallet-tab-bar.mjs.map +1 -1
- package/dist/ui/mount.mjs.map +1 -1
- package/dist/ui/styles.mjs.map +1 -1
- package/dist/ui/transaction-analyzer.mjs.map +1 -1
- package/dist/ui/utils.d.mts.map +1 -1
- package/dist/ui/utils.mjs.map +1 -1
- package/dist/ui/wallet-controller.mjs.map +1 -1
- package/dist/wallet/constants.d.mts.map +1 -1
- package/dist/wallet/constants.mjs.map +1 -1
- package/dist/wallet/dev-wallet.d.mts +19 -0
- package/dist/wallet/dev-wallet.d.mts.map +1 -1
- package/dist/wallet/dev-wallet.mjs +58 -2
- package/dist/wallet/dev-wallet.mjs.map +1 -1
- package/dist/wallet/initializer.d.mts.map +1 -1
- package/dist/wallet/initializer.mjs +10 -26
- package/dist/wallet/initializer.mjs.map +1 -1
- package/dist/wallet/mount-and-register.d.mts +44 -0
- package/dist/wallet/mount-and-register.d.mts.map +1 -0
- package/dist/wallet/mount-and-register.mjs +46 -0
- package/dist/wallet/mount-and-register.mjs.map +1 -0
- package/dist/wallet/signing.d.mts.map +1 -1
- package/dist/wallet/signing.mjs.map +1 -1
- package/package.json +26 -22
- package/src/adapters/devstack-paths.ts +0 -1
- package/src/index.ts +5 -0
- package/src/inject/index.ts +183 -0
- package/src/react/useDevWallet.ts +26 -71
- package/src/ui/dev-wallet-signing.ts +2 -0
- package/src/wallet/dev-wallet.ts +75 -2
- package/src/wallet/initializer.ts +16 -42
- package/src/wallet/mount-and-register.ts +93 -0
- package/dist/standalone/assets/in-memory-adapter-qRkNfj9O.js +0 -1
- package/dist/standalone/assets/main-DDltQnzR.js +0 -3954
- package/dist/standalone/assets/webcrypto-adapter-FejcrL9x.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-cli-adapter.mjs","names":["#address","#publicKey","#scheme","#serverOrigin","#authToken","#fetchServerAccounts","#restoreImportedAccounts","#allServerAccounts","#serverAccountToManaged","#saveImportedAddresses","#lastFetch","#authHeaders","#loadImportedAddresses"],"sources":["../../src/adapters/remote-cli-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Signer } from '@mysten/sui/cryptography';\nimport type { PublicKey, SignatureScheme } from '@mysten/sui/cryptography';\nimport { Ed25519PublicKey } from '@mysten/sui/keypairs/ed25519';\nimport { Secp256k1PublicKey } from '@mysten/sui/keypairs/secp256k1';\nimport { Secp256r1PublicKey } from '@mysten/sui/keypairs/secp256r1';\nimport { fromBase64, toBase64 } from '@mysten/sui/utils';\nimport type { ImportAccountOptions, ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\n\n/**\n * Wallet features advertised by CLI-backed accounts.\n * Personal message signing is not supported because the `sui keytool sign`\n * command only accepts BCS-serialized TransactionData.\n */\nconst CLI_WALLET_FEATURES = ['sui:signTransaction', 'sui:signAndExecuteTransaction'] as const;\n\n/** Cache TTL for the CLI server accounts fetch (milliseconds). */\nconst ACCOUNTS_CACHE_TTL_MS = 5000;\n\n/** Thrown when the server rejects a request with a 401 or 403 status. */\nclass AuthError extends Error {\n\tconstructor() {\n\t\tsuper('Unauthorized');\n\t\tthis.name = 'AuthError';\n\t}\n}\n\n/** Map CLI `keyScheme` strings to SDK {@link SignatureScheme} values. */\nconst KEY_SCHEME_MAP: Record<string, SignatureScheme> = {\n\ted25519: 'ED25519',\n\tsecp256k1: 'Secp256k1',\n\tsecp256r1: 'Secp256r1',\n};\n\n/** Account metadata returned by the server `/api/v1/accounts` endpoint. */\ninterface ServerAccountInfo {\n\tsuiAddress: string;\n\tpublicBase64Key: string;\n\tkeyScheme: string;\n\talias: string | null;\n}\n\nfunction publicKeyFromSuiBytes(publicBase64Key: string, scheme: SignatureScheme): PublicKey {\n\tconst allBytes = fromBase64(publicBase64Key);\n\tconst rawBytes = allBytes.slice(1);\n\n\tswitch (scheme) {\n\t\tcase 'ED25519':\n\t\t\treturn new Ed25519PublicKey(rawBytes);\n\t\tcase 'Secp256k1':\n\t\t\treturn new Secp256k1PublicKey(rawBytes);\n\t\tcase 'Secp256r1':\n\t\t\treturn new Secp256r1PublicKey(rawBytes);\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported key scheme: ${scheme}`);\n\t}\n}\n\n/**\n * A {@link Signer} that delegates transaction signing to a server HTTP endpoint\n * backed by `sui keytool sign`. Private keys never enter JavaScript.\n *\n * `signPersonalMessage()` is not supported — `sui keytool sign` only accepts\n * BCS-serialized `TransactionData`.\n */\nexport class CliProxySigner extends Signer {\n\t#address: string;\n\t#publicKey: PublicKey;\n\t#scheme: SignatureScheme;\n\t#serverOrigin: string;\n\t#authToken: string | null;\n\n\tconstructor(options: {\n\t\taddress: string;\n\t\tpublicKey: PublicKey;\n\t\tscheme: SignatureScheme;\n\t\tserverOrigin: string;\n\t\tauthToken?: string | null;\n\t}) {\n\t\tsuper();\n\t\tthis.#address = options.address;\n\t\tthis.#publicKey = options.publicKey;\n\t\tthis.#scheme = options.scheme;\n\t\tthis.#serverOrigin = options.serverOrigin;\n\t\tthis.#authToken = options.authToken ?? null;\n\t}\n\n\tasync sign(_bytes: Uint8Array): Promise<Uint8Array<ArrayBuffer>> {\n\t\tthrow new Error(\n\t\t\t'CliProxySigner does not support direct digest signing. ' +\n\t\t\t\t'Transaction signing is handled via the sui CLI.',\n\t\t);\n\t}\n\n\tgetKeyScheme(): SignatureScheme {\n\t\treturn this.#scheme;\n\t}\n\n\tgetPublicKey(): PublicKey {\n\t\treturn this.#publicKey;\n\t}\n\n\toverride toSuiAddress(): string {\n\t\treturn this.#address;\n\t}\n\n\toverride async signTransaction(bytes: Uint8Array) {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\n\t\tconst res = await fetch(`${this.#serverOrigin}/api/v1/sign-transaction`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({\n\t\t\t\taddress: this.#address,\n\t\t\t\ttxBytes: toBase64(bytes),\n\t\t\t}),\n\t\t});\n\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.json().catch(() => ({}));\n\t\t\tthrow new Error(`Transaction signing failed: ${body.error ?? res.statusText}`);\n\t\t}\n\n\t\tconst { suiSignature } = await res.json();\n\t\tif (typeof suiSignature !== 'string' || suiSignature.length === 0) {\n\t\t\tthrow new Error('Transaction signing failed: server returned invalid signature');\n\t\t}\n\t\treturn {\n\t\t\tbytes: toBase64(bytes),\n\t\t\tsignature: suiSignature,\n\t\t};\n\t}\n\n\toverride async signPersonalMessage(_bytes: Uint8Array): Promise<never> {\n\t\tthrow new Error(\n\t\t\t'Personal message signing is not supported in CLI mode. ' +\n\t\t\t\t'The sui keytool sign command only supports TransactionData. ' +\n\t\t\t\t'Use --adapter=webcrypto or --adapter=memory for personal message signing.',\n\t\t);\n\t}\n}\n\n/**\n * {@link SignerAdapter} that delegates signing to a server running the `sui` CLI.\n *\n * Authentication uses a token-in-URL approach: the CLI server prints a URL with\n * a token, which gets stored in `localStorage` for subsequent page loads. Imported\n * account addresses are also persisted so they survive CLI restarts.\n */\nexport class RemoteCliAdapter extends BaseSignerAdapter {\n\treadonly id = 'remote-cli';\n\treadonly name = 'Remote CLI Signer';\n\treadonly allowAutoSign = false;\n\n\tprotected override getDefaultLabel(): string {\n\t\treturn `CLI Account ${this.getAccounts().length + 1}`;\n\t}\n\n\t// Keys are scoped per origin to prevent cross-site leakage on shared localhost setups.\n\t// localStorage is used rather than sessionStorage because popup wallet flows\n\t// (DevWalletClient) may open new tabs that need access to the token.\n\tstatic storageKey(suffix: string): string {\n\t\tconst origin = typeof location !== 'undefined' ? location.origin : 'unknown';\n\t\treturn `dev-wallet:${suffix}:${origin}`;\n\t}\n\n\tstatic get STORAGE_KEY(): string {\n\t\treturn RemoteCliAdapter.storageKey('cli-imported-addresses');\n\t}\n\n\tstatic get TOKEN_KEY(): string {\n\t\treturn RemoteCliAdapter.storageKey('cli-token');\n\t}\n\n\t#serverOrigin: string;\n\t#authToken: string | null = null;\n\t#allServerAccounts: ServerAccountInfo[] = [];\n\t#lastFetch: { time: number; result: ServerAccountInfo[] } | null = null;\n\n\tconstructor(options?: { serverOrigin?: string; token?: string }) {\n\t\tsuper();\n\t\tconst origin = options?.serverOrigin ?? '';\n\t\tif (origin) {\n\t\t\ttry {\n\t\t\t\tnew URL(origin);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Invalid serverOrigin URL: \"${origin}\"`);\n\t\t\t}\n\t\t}\n\t\tthis.#serverOrigin = origin;\n\t\tif (options?.token) {\n\t\t\tthis.#authToken = options.token;\n\t\t}\n\t}\n\n\tget isPaired(): boolean {\n\t\treturn this.#authToken !== null;\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tif (!this.#authToken && typeof localStorage !== 'undefined') {\n\t\t\tconst stored = localStorage.getItem(RemoteCliAdapter.TOKEN_KEY);\n\t\t\tif (stored) {\n\t\t\t\tthis.#authToken = stored;\n\t\t\t}\n\t\t}\n\n\t\tif (this.#authToken) {\n\t\t\ttry {\n\t\t\t\tawait this.#fetchServerAccounts();\n\t\t\t\tawait this.#restoreImportedAccounts();\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof AuthError) {\n\t\t\t\t\tthis.#authToken = null;\n\t\t\t\t\tif (typeof localStorage !== 'undefined') {\n\t\t\t\t\t\tlocalStorage.removeItem(RemoteCliAdapter.TOKEN_KEY);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn('[dev-wallet] CLI adapter initialization failed:', error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync listAvailableAccounts(): Promise<\n\t\tArray<{ address: string; scheme: string; alias: string | null }>\n\t> {\n\t\tawait this.#fetchServerAccounts();\n\t\tconst importedAddresses = new Set(this._accounts.map((a) => a.address));\n\t\treturn this.#allServerAccounts\n\t\t\t.filter((info) => {\n\t\t\t\tconst scheme = KEY_SCHEME_MAP[info.keyScheme];\n\t\t\t\treturn scheme && !importedAddresses.has(info.suiAddress);\n\t\t\t})\n\t\t\t.map((info) => ({\n\t\t\t\taddress: info.suiAddress,\n\t\t\t\tscheme: info.keyScheme,\n\t\t\t\talias: info.alias,\n\t\t\t}));\n\t}\n\n\tasync importAccount(options: ImportAccountOptions): Promise<ManagedAccount> {\n\t\tconst address = options.address;\n\t\tif (!address) {\n\t\t\tthrow new Error('Remote CLI adapter requires an address to import');\n\t\t}\n\n\t\tif (this._accounts.some((a) => a.address === address)) {\n\t\t\tthrow new Error(`Account ${address} is already imported`);\n\t\t}\n\n\t\tawait this.#fetchServerAccounts();\n\t\tconst info = this.#allServerAccounts.find((a) => a.suiAddress === address);\n\t\tif (!info) {\n\t\t\tthrow new Error(`Account ${address} not found on server`);\n\t\t}\n\n\t\tconst scheme = KEY_SCHEME_MAP[info.keyScheme];\n\t\tif (!scheme) {\n\t\t\tthrow new Error(`Unsupported key scheme: ${info.keyScheme}`);\n\t\t}\n\n\t\tconst account = this.#serverAccountToManaged(info, scheme, options.label);\n\t\tthis.addAccount(account);\n\t\tthis.#saveImportedAddresses();\n\t\treturn account;\n\t}\n\n\tasync removeAccount(address: string): Promise<boolean> {\n\t\tconst removed = this.removeAccountByAddress(address);\n\t\tif (removed) {\n\t\t\tthis.#saveImportedAddresses();\n\t\t}\n\t\treturn removed;\n\t}\n\n\toverride destroy(): void {\n\t\tthis.#allServerAccounts = [];\n\t\tthis.#authToken = null;\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.removeItem(RemoteCliAdapter.TOKEN_KEY);\n\t\t\tlocalStorage.removeItem(RemoteCliAdapter.STORAGE_KEY);\n\t\t}\n\t\tsuper.destroy();\n\t}\n\n\t#authHeaders(): Record<string, string> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\treturn headers;\n\t}\n\n\tasync #fetchServerAccounts(forceRefresh = false): Promise<void> {\n\t\tif (\n\t\t\t!forceRefresh &&\n\t\t\tthis.#lastFetch &&\n\t\t\tDate.now() - this.#lastFetch.time < ACCOUNTS_CACHE_TTL_MS\n\t\t) {\n\t\t\tthis.#allServerAccounts = this.#lastFetch.result;\n\t\t\treturn;\n\t\t}\n\t\tconst res = await fetch(`${this.#serverOrigin}/api/v1/accounts`, {\n\t\t\theaders: this.#authHeaders(),\n\t\t});\n\t\tif (res.status === 401 || res.status === 403) {\n\t\t\tthrow new AuthError();\n\t\t}\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`Failed to fetch accounts: ${res.statusText}`);\n\t\t}\n\n\t\tconst { accounts } = (await res.json()) as { accounts: ServerAccountInfo[] };\n\t\tthis.#allServerAccounts = accounts;\n\t\tthis.#lastFetch = { time: Date.now(), result: accounts };\n\t}\n\n\tasync #restoreImportedAccounts(): Promise<void> {\n\t\tconst saved = this.#loadImportedAddresses();\n\t\tif (saved.length === 0) return;\n\n\t\tconst existingAddresses = new Set(this.getAccounts().map((a) => a.address));\n\t\tconst restored: ManagedAccount[] = [];\n\n\t\tfor (const address of saved) {\n\t\t\tif (existingAddresses.has(address)) continue;\n\n\t\t\tconst info = this.#allServerAccounts.find((a) => a.suiAddress === address);\n\t\t\tif (!info) continue; // Account no longer on server — skip\n\n\t\t\tconst scheme = KEY_SCHEME_MAP[info.keyScheme];\n\t\t\tif (!scheme) continue;\n\n\t\t\trestored.push(this.#serverAccountToManaged(info, scheme));\n\t\t}\n\n\t\tif (restored.length > 0) {\n\t\t\tthis.setInitialAccounts([...this.getAccounts(), ...restored]);\n\t\t}\n\t}\n\n\t#loadImportedAddresses(): string[] {\n\t\tif (typeof localStorage === 'undefined') return [];\n\t\ttry {\n\t\t\tconst raw = localStorage.getItem(RemoteCliAdapter.STORAGE_KEY);\n\t\t\tif (!raw) return [];\n\t\t\tconst parsed: unknown = JSON.parse(raw);\n\t\t\tif (!Array.isArray(parsed)) return [];\n\t\t\treturn parsed.filter((v): v is string => typeof v === 'string');\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t#saveImportedAddresses(): void {\n\t\tif (typeof localStorage === 'undefined') return;\n\t\tconst addresses = this._accounts.map((a) => a.address);\n\t\tlocalStorage.setItem(RemoteCliAdapter.STORAGE_KEY, JSON.stringify(addresses));\n\t}\n\n\t#serverAccountToManaged(\n\t\tinfo: ServerAccountInfo,\n\t\tscheme: SignatureScheme,\n\t\tlabel?: string,\n\t): ManagedAccount {\n\t\tconst publicKey = publicKeyFromSuiBytes(info.publicBase64Key, scheme);\n\n\t\tconst signer = new CliProxySigner({\n\t\t\taddress: info.suiAddress,\n\t\t\tpublicKey,\n\t\t\tscheme,\n\t\t\tserverOrigin: this.#serverOrigin,\n\t\t\tauthToken: this.#authToken,\n\t\t});\n\n\t\tconst accountLabel = label ?? info.alias ?? this.getDefaultLabel();\n\n\t\treturn buildManagedAccount(signer, info.suiAddress, accountLabel, CLI_WALLET_FEATURES);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"remote-cli-adapter.mjs","names":["#address","#publicKey","#scheme","#serverOrigin","#authToken","#fetchServerAccounts","#restoreImportedAccounts","#allServerAccounts","#serverAccountToManaged","#saveImportedAddresses","#lastFetch","#authHeaders","#loadImportedAddresses"],"sources":["../../src/adapters/remote-cli-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Signer } from '@mysten/sui/cryptography';\nimport type { PublicKey, SignatureScheme } from '@mysten/sui/cryptography';\nimport { Ed25519PublicKey } from '@mysten/sui/keypairs/ed25519';\nimport { Secp256k1PublicKey } from '@mysten/sui/keypairs/secp256k1';\nimport { Secp256r1PublicKey } from '@mysten/sui/keypairs/secp256r1';\nimport { fromBase64, toBase64 } from '@mysten/sui/utils';\nimport type { ImportAccountOptions, ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\n\n/**\n * Wallet features advertised by CLI-backed accounts.\n * Personal message signing is not supported because the `sui keytool sign`\n * command only accepts BCS-serialized TransactionData.\n */\nconst CLI_WALLET_FEATURES = ['sui:signTransaction', 'sui:signAndExecuteTransaction'] as const;\n\n/** Cache TTL for the CLI server accounts fetch (milliseconds). */\nconst ACCOUNTS_CACHE_TTL_MS = 5000;\n\n/** Thrown when the server rejects a request with a 401 or 403 status. */\nclass AuthError extends Error {\n\tconstructor() {\n\t\tsuper('Unauthorized');\n\t\tthis.name = 'AuthError';\n\t}\n}\n\n/** Map CLI `keyScheme` strings to SDK {@link SignatureScheme} values. */\nconst KEY_SCHEME_MAP: Record<string, SignatureScheme> = {\n\ted25519: 'ED25519',\n\tsecp256k1: 'Secp256k1',\n\tsecp256r1: 'Secp256r1',\n};\n\n/** Account metadata returned by the server `/api/v1/accounts` endpoint. */\ninterface ServerAccountInfo {\n\tsuiAddress: string;\n\tpublicBase64Key: string;\n\tkeyScheme: string;\n\talias: string | null;\n}\n\nfunction publicKeyFromSuiBytes(publicBase64Key: string, scheme: SignatureScheme): PublicKey {\n\tconst allBytes = fromBase64(publicBase64Key);\n\tconst rawBytes = allBytes.slice(1);\n\n\tswitch (scheme) {\n\t\tcase 'ED25519':\n\t\t\treturn new Ed25519PublicKey(rawBytes);\n\t\tcase 'Secp256k1':\n\t\t\treturn new Secp256k1PublicKey(rawBytes);\n\t\tcase 'Secp256r1':\n\t\t\treturn new Secp256r1PublicKey(rawBytes);\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported key scheme: ${scheme}`);\n\t}\n}\n\n/**\n * A {@link Signer} that delegates transaction signing to a server HTTP endpoint\n * backed by `sui keytool sign`. Private keys never enter JavaScript.\n *\n * `signPersonalMessage()` is not supported — `sui keytool sign` only accepts\n * BCS-serialized `TransactionData`.\n */\nexport class CliProxySigner extends Signer {\n\t#address: string;\n\t#publicKey: PublicKey;\n\t#scheme: SignatureScheme;\n\t#serverOrigin: string;\n\t#authToken: string | null;\n\n\tconstructor(options: {\n\t\taddress: string;\n\t\tpublicKey: PublicKey;\n\t\tscheme: SignatureScheme;\n\t\tserverOrigin: string;\n\t\tauthToken?: string | null;\n\t}) {\n\t\tsuper();\n\t\tthis.#address = options.address;\n\t\tthis.#publicKey = options.publicKey;\n\t\tthis.#scheme = options.scheme;\n\t\tthis.#serverOrigin = options.serverOrigin;\n\t\tthis.#authToken = options.authToken ?? null;\n\t}\n\n\tasync sign(_bytes: Uint8Array): Promise<Uint8Array<ArrayBuffer>> {\n\t\tthrow new Error(\n\t\t\t'CliProxySigner does not support direct digest signing. ' +\n\t\t\t\t'Transaction signing is handled via the sui CLI.',\n\t\t);\n\t}\n\n\tgetKeyScheme(): SignatureScheme {\n\t\treturn this.#scheme;\n\t}\n\n\tgetPublicKey(): PublicKey {\n\t\treturn this.#publicKey;\n\t}\n\n\toverride toSuiAddress(): string {\n\t\treturn this.#address;\n\t}\n\n\toverride async signTransaction(bytes: Uint8Array) {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\n\t\tconst res = await fetch(`${this.#serverOrigin}/api/v1/sign-transaction`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({\n\t\t\t\taddress: this.#address,\n\t\t\t\ttxBytes: toBase64(bytes),\n\t\t\t}),\n\t\t});\n\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.json().catch(() => ({}));\n\t\t\tthrow new Error(`Transaction signing failed: ${body.error ?? res.statusText}`);\n\t\t}\n\n\t\tconst { suiSignature } = await res.json();\n\t\tif (typeof suiSignature !== 'string' || suiSignature.length === 0) {\n\t\t\tthrow new Error('Transaction signing failed: server returned invalid signature');\n\t\t}\n\t\treturn {\n\t\t\tbytes: toBase64(bytes),\n\t\t\tsignature: suiSignature,\n\t\t};\n\t}\n\n\toverride async signPersonalMessage(_bytes: Uint8Array): Promise<never> {\n\t\tthrow new Error(\n\t\t\t'Personal message signing is not supported in CLI mode. ' +\n\t\t\t\t'The sui keytool sign command only supports TransactionData. ' +\n\t\t\t\t'Use --adapter=webcrypto or --adapter=memory for personal message signing.',\n\t\t);\n\t}\n}\n\n/**\n * {@link SignerAdapter} that delegates signing to a server running the `sui` CLI.\n *\n * Authentication uses a token-in-URL approach: the CLI server prints a URL with\n * a token, which gets stored in `localStorage` for subsequent page loads. Imported\n * account addresses are also persisted so they survive CLI restarts.\n */\nexport class RemoteCliAdapter extends BaseSignerAdapter {\n\treadonly id = 'remote-cli';\n\treadonly name = 'Remote CLI Signer';\n\treadonly allowAutoSign = false;\n\n\tprotected override getDefaultLabel(): string {\n\t\treturn `CLI Account ${this.getAccounts().length + 1}`;\n\t}\n\n\t// Keys are scoped per origin to prevent cross-site leakage on shared localhost setups.\n\t// localStorage is used rather than sessionStorage because popup wallet flows\n\t// (DevWalletClient) may open new tabs that need access to the token.\n\tstatic storageKey(suffix: string): string {\n\t\tconst origin = typeof location !== 'undefined' ? location.origin : 'unknown';\n\t\treturn `dev-wallet:${suffix}:${origin}`;\n\t}\n\n\tstatic get STORAGE_KEY(): string {\n\t\treturn RemoteCliAdapter.storageKey('cli-imported-addresses');\n\t}\n\n\tstatic get TOKEN_KEY(): string {\n\t\treturn RemoteCliAdapter.storageKey('cli-token');\n\t}\n\n\t#serverOrigin: string;\n\t#authToken: string | null = null;\n\t#allServerAccounts: ServerAccountInfo[] = [];\n\t#lastFetch: { time: number; result: ServerAccountInfo[] } | null = null;\n\n\tconstructor(options?: { serverOrigin?: string; token?: string }) {\n\t\tsuper();\n\t\tconst origin = options?.serverOrigin ?? '';\n\t\tif (origin) {\n\t\t\ttry {\n\t\t\t\tnew URL(origin);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Invalid serverOrigin URL: \"${origin}\"`);\n\t\t\t}\n\t\t}\n\t\tthis.#serverOrigin = origin;\n\t\tif (options?.token) {\n\t\t\tthis.#authToken = options.token;\n\t\t}\n\t}\n\n\tget isPaired(): boolean {\n\t\treturn this.#authToken !== null;\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tif (!this.#authToken && typeof localStorage !== 'undefined') {\n\t\t\tconst stored = localStorage.getItem(RemoteCliAdapter.TOKEN_KEY);\n\t\t\tif (stored) {\n\t\t\t\tthis.#authToken = stored;\n\t\t\t}\n\t\t}\n\n\t\tif (this.#authToken) {\n\t\t\ttry {\n\t\t\t\tawait this.#fetchServerAccounts();\n\t\t\t\tawait this.#restoreImportedAccounts();\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof AuthError) {\n\t\t\t\t\tthis.#authToken = null;\n\t\t\t\t\tif (typeof localStorage !== 'undefined') {\n\t\t\t\t\t\tlocalStorage.removeItem(RemoteCliAdapter.TOKEN_KEY);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn('[dev-wallet] CLI adapter initialization failed:', error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync listAvailableAccounts(): Promise<\n\t\tArray<{ address: string; scheme: string; alias: string | null }>\n\t> {\n\t\tawait this.#fetchServerAccounts();\n\t\tconst importedAddresses = new Set(this._accounts.map((a) => a.address));\n\t\treturn this.#allServerAccounts\n\t\t\t.filter((info) => {\n\t\t\t\tconst scheme = KEY_SCHEME_MAP[info.keyScheme];\n\t\t\t\treturn scheme && !importedAddresses.has(info.suiAddress);\n\t\t\t})\n\t\t\t.map((info) => ({\n\t\t\t\taddress: info.suiAddress,\n\t\t\t\tscheme: info.keyScheme,\n\t\t\t\talias: info.alias,\n\t\t\t}));\n\t}\n\n\tasync importAccount(options: ImportAccountOptions): Promise<ManagedAccount> {\n\t\tconst address = options.address;\n\t\tif (!address) {\n\t\t\tthrow new Error('Remote CLI adapter requires an address to import');\n\t\t}\n\n\t\tif (this._accounts.some((a) => a.address === address)) {\n\t\t\tthrow new Error(`Account ${address} is already imported`);\n\t\t}\n\n\t\tawait this.#fetchServerAccounts();\n\t\tconst info = this.#allServerAccounts.find((a) => a.suiAddress === address);\n\t\tif (!info) {\n\t\t\tthrow new Error(`Account ${address} not found on server`);\n\t\t}\n\n\t\tconst scheme = KEY_SCHEME_MAP[info.keyScheme];\n\t\tif (!scheme) {\n\t\t\tthrow new Error(`Unsupported key scheme: ${info.keyScheme}`);\n\t\t}\n\n\t\tconst account = this.#serverAccountToManaged(info, scheme, options.label);\n\t\tthis.addAccount(account);\n\t\tthis.#saveImportedAddresses();\n\t\treturn account;\n\t}\n\n\tasync removeAccount(address: string): Promise<boolean> {\n\t\tconst removed = this.removeAccountByAddress(address);\n\t\tif (removed) {\n\t\t\tthis.#saveImportedAddresses();\n\t\t}\n\t\treturn removed;\n\t}\n\n\toverride destroy(): void {\n\t\tthis.#allServerAccounts = [];\n\t\tthis.#authToken = null;\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.removeItem(RemoteCliAdapter.TOKEN_KEY);\n\t\t\tlocalStorage.removeItem(RemoteCliAdapter.STORAGE_KEY);\n\t\t}\n\t\tsuper.destroy();\n\t}\n\n\t#authHeaders(): Record<string, string> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\treturn headers;\n\t}\n\n\tasync #fetchServerAccounts(forceRefresh = false): Promise<void> {\n\t\tif (\n\t\t\t!forceRefresh &&\n\t\t\tthis.#lastFetch &&\n\t\t\tDate.now() - this.#lastFetch.time < ACCOUNTS_CACHE_TTL_MS\n\t\t) {\n\t\t\tthis.#allServerAccounts = this.#lastFetch.result;\n\t\t\treturn;\n\t\t}\n\t\tconst res = await fetch(`${this.#serverOrigin}/api/v1/accounts`, {\n\t\t\theaders: this.#authHeaders(),\n\t\t});\n\t\tif (res.status === 401 || res.status === 403) {\n\t\t\tthrow new AuthError();\n\t\t}\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`Failed to fetch accounts: ${res.statusText}`);\n\t\t}\n\n\t\tconst { accounts } = (await res.json()) as { accounts: ServerAccountInfo[] };\n\t\tthis.#allServerAccounts = accounts;\n\t\tthis.#lastFetch = { time: Date.now(), result: accounts };\n\t}\n\n\tasync #restoreImportedAccounts(): Promise<void> {\n\t\tconst saved = this.#loadImportedAddresses();\n\t\tif (saved.length === 0) return;\n\n\t\tconst existingAddresses = new Set(this.getAccounts().map((a) => a.address));\n\t\tconst restored: ManagedAccount[] = [];\n\n\t\tfor (const address of saved) {\n\t\t\tif (existingAddresses.has(address)) continue;\n\n\t\t\tconst info = this.#allServerAccounts.find((a) => a.suiAddress === address);\n\t\t\tif (!info) continue; // Account no longer on server — skip\n\n\t\t\tconst scheme = KEY_SCHEME_MAP[info.keyScheme];\n\t\t\tif (!scheme) continue;\n\n\t\t\trestored.push(this.#serverAccountToManaged(info, scheme));\n\t\t}\n\n\t\tif (restored.length > 0) {\n\t\t\tthis.setInitialAccounts([...this.getAccounts(), ...restored]);\n\t\t}\n\t}\n\n\t#loadImportedAddresses(): string[] {\n\t\tif (typeof localStorage === 'undefined') return [];\n\t\ttry {\n\t\t\tconst raw = localStorage.getItem(RemoteCliAdapter.STORAGE_KEY);\n\t\t\tif (!raw) return [];\n\t\t\tconst parsed: unknown = JSON.parse(raw);\n\t\t\tif (!Array.isArray(parsed)) return [];\n\t\t\treturn parsed.filter((v): v is string => typeof v === 'string');\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t#saveImportedAddresses(): void {\n\t\tif (typeof localStorage === 'undefined') return;\n\t\tconst addresses = this._accounts.map((a) => a.address);\n\t\tlocalStorage.setItem(RemoteCliAdapter.STORAGE_KEY, JSON.stringify(addresses));\n\t}\n\n\t#serverAccountToManaged(\n\t\tinfo: ServerAccountInfo,\n\t\tscheme: SignatureScheme,\n\t\tlabel?: string,\n\t): ManagedAccount {\n\t\tconst publicKey = publicKeyFromSuiBytes(info.publicBase64Key, scheme);\n\n\t\tconst signer = new CliProxySigner({\n\t\t\taddress: info.suiAddress,\n\t\t\tpublicKey,\n\t\t\tscheme,\n\t\t\tserverOrigin: this.#serverOrigin,\n\t\t\tauthToken: this.#authToken,\n\t\t});\n\n\t\tconst accountLabel = label ?? info.alias ?? this.getDefaultLabel();\n\n\t\treturn buildManagedAccount(signer, info.suiAddress, accountLabel, CLI_WALLET_FEATURES);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webcrypto-adapter.d.mts","names":[],"sources":["../../src/adapters/webcrypto-adapter.ts"],"mappings":";;;;cAoBa,sBAAA,SAA+B,iBAAA;EAAA;WAClC,EAAA;EAAA,SACA,IAAA;cAIG,OAAA;IAAY,MAAA;IAAiB,SAAA;EAAA;EAQnC,UAAA,
|
|
1
|
+
{"version":3,"file":"webcrypto-adapter.d.mts","names":[],"sources":["../../src/adapters/webcrypto-adapter.ts"],"mappings":";;;;cAoBa,sBAAA,SAA+B,iBAAA;EAAA;WAClC,EAAA;EAAA,SACA,IAAA;cAIG,OAAA;IAAY,MAAA;IAAiB,SAAA;EAAA;EAQnC,UAAA,IAAc,OAAA;EA0Bd,aAAA,CAAc,OAAA,GAAU,oBAAA,GAAuB,OAAA,CAAQ,cAAA;EAcvD,aAAA,CAAc,OAAA,UAAiB,KAAA,WAAgB,OAAA;EAM/C,aAAA,CAAc,OAAA,WAAkB,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webcrypto-adapter.mjs","names":["#store","#saveMeta"],"sources":["../../src/adapters/webcrypto-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ExportedWebCryptoKeypair } from '@mysten/signers/webcrypto';\nimport { WebCryptoSigner } from '@mysten/signers/webcrypto';\n\nimport type { CreateAccountOptions, ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\nimport { IDBStore } from './idb-store.js';\n\ninterface StoredAccountMeta {\n\taddress: string;\n\tlabel: string;\n}\n\nconst DEFAULT_DB_NAME = 'dev-wallet-webcrypto';\nconst DEFAULT_STORE_NAME = 'accounts';\nconst META_KEY = '__account_meta__';\n\nexport class WebCryptoSignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'webcrypto';\n\treadonly name = 'WebCrypto Signer';\n\n\t#store: IDBStore;\n\n\tconstructor(options?: { dbName?: string; storeName?: string }) {\n\t\tsuper();\n\t\tthis.#store = new IDBStore(\n\t\t\toptions?.dbName ?? DEFAULT_DB_NAME,\n\t\t\toptions?.storeName ?? DEFAULT_STORE_NAME,\n\t\t);\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tconst allEntries = await this.#store.entries<\n\t\t\tstring,\n\t\t\tExportedWebCryptoKeypair | StoredAccountMeta[]\n\t\t>();\n\t\tconst meta: StoredAccountMeta[] = (await this.#store.get<StoredAccountMeta[]>(META_KEY)) ?? [];\n\n\t\tconst accounts = [];\n\n\t\tfor (const [key, value] of allEntries) {\n\t\t\tif (key === META_KEY) continue;\n\n\t\t\tconst address = key as string;\n\t\t\ttry {\n\t\t\t\tconst exported = value as ExportedWebCryptoKeypair;\n\t\t\t\tconst signer = WebCryptoSigner.import(exported);\n\t\t\t\tconst accountMeta = meta.find((m) => m.address === address);\n\t\t\t\taccounts.push(buildManagedAccount(signer, address, accountMeta?.label ?? 'Account'));\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(`[dev-wallet] Failed to load account ${address}, skipping:`, error);\n\t\t\t}\n\t\t}\n\n\t\tthis.setInitialAccounts(accounts);\n\t}\n\n\tasync createAccount(options?: CreateAccountOptions): Promise<ManagedAccount> {\n\t\tconst signer = await WebCryptoSigner.generate();\n\t\tconst address = signer.getPublicKey().toSuiAddress();\n\t\tconst label = options?.label ?? this.getDefaultLabel();\n\n\t\tconst managedAccount = buildManagedAccount(signer, address, label);\n\n\t\tawait this.#store.set(address, signer.export());\n\t\tthis.addAccount(managedAccount);\n\t\tawait this.#saveMeta();\n\n\t\treturn managedAccount;\n\t}\n\n\tasync renameAccount(address: string, label: string): Promise<boolean> {\n\t\tif (!this._performRename(address, label)) return false;\n\t\tawait this.#saveMeta();\n\t\treturn true;\n\t}\n\n\tasync removeAccount(address: string): Promise<boolean> {\n\t\tif (!this.removeAccountByAddress(address)) return false;\n\n\t\tawait this.#store.del(address);\n\t\tawait this.#saveMeta();\n\t\treturn true;\n\t}\n\n\tasync #saveMeta(): Promise<void> {\n\t\tconst meta: StoredAccountMeta[] = this.getAccounts().map((a) => ({\n\t\t\taddress: a.address,\n\t\t\tlabel: a.label,\n\t\t}));\n\t\tawait this.#store.set(META_KEY, meta);\n\t}\n}\n"],"mappings":";;;;;AAgBA,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,WAAW;AAEjB,IAAa,yBAAb,cAA4C,kBAAkB;CAI7D;CAEA,YAAY,SAAmD;
|
|
1
|
+
{"version":3,"file":"webcrypto-adapter.mjs","names":["#store","#saveMeta"],"sources":["../../src/adapters/webcrypto-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ExportedWebCryptoKeypair } from '@mysten/signers/webcrypto';\nimport { WebCryptoSigner } from '@mysten/signers/webcrypto';\n\nimport type { CreateAccountOptions, ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\nimport { IDBStore } from './idb-store.js';\n\ninterface StoredAccountMeta {\n\taddress: string;\n\tlabel: string;\n}\n\nconst DEFAULT_DB_NAME = 'dev-wallet-webcrypto';\nconst DEFAULT_STORE_NAME = 'accounts';\nconst META_KEY = '__account_meta__';\n\nexport class WebCryptoSignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'webcrypto';\n\treadonly name = 'WebCrypto Signer';\n\n\t#store: IDBStore;\n\n\tconstructor(options?: { dbName?: string; storeName?: string }) {\n\t\tsuper();\n\t\tthis.#store = new IDBStore(\n\t\t\toptions?.dbName ?? DEFAULT_DB_NAME,\n\t\t\toptions?.storeName ?? DEFAULT_STORE_NAME,\n\t\t);\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tconst allEntries = await this.#store.entries<\n\t\t\tstring,\n\t\t\tExportedWebCryptoKeypair | StoredAccountMeta[]\n\t\t>();\n\t\tconst meta: StoredAccountMeta[] = (await this.#store.get<StoredAccountMeta[]>(META_KEY)) ?? [];\n\n\t\tconst accounts = [];\n\n\t\tfor (const [key, value] of allEntries) {\n\t\t\tif (key === META_KEY) continue;\n\n\t\t\tconst address = key as string;\n\t\t\ttry {\n\t\t\t\tconst exported = value as ExportedWebCryptoKeypair;\n\t\t\t\tconst signer = WebCryptoSigner.import(exported);\n\t\t\t\tconst accountMeta = meta.find((m) => m.address === address);\n\t\t\t\taccounts.push(buildManagedAccount(signer, address, accountMeta?.label ?? 'Account'));\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(`[dev-wallet] Failed to load account ${address}, skipping:`, error);\n\t\t\t}\n\t\t}\n\n\t\tthis.setInitialAccounts(accounts);\n\t}\n\n\tasync createAccount(options?: CreateAccountOptions): Promise<ManagedAccount> {\n\t\tconst signer = await WebCryptoSigner.generate();\n\t\tconst address = signer.getPublicKey().toSuiAddress();\n\t\tconst label = options?.label ?? this.getDefaultLabel();\n\n\t\tconst managedAccount = buildManagedAccount(signer, address, label);\n\n\t\tawait this.#store.set(address, signer.export());\n\t\tthis.addAccount(managedAccount);\n\t\tawait this.#saveMeta();\n\n\t\treturn managedAccount;\n\t}\n\n\tasync renameAccount(address: string, label: string): Promise<boolean> {\n\t\tif (!this._performRename(address, label)) return false;\n\t\tawait this.#saveMeta();\n\t\treturn true;\n\t}\n\n\tasync removeAccount(address: string): Promise<boolean> {\n\t\tif (!this.removeAccountByAddress(address)) return false;\n\n\t\tawait this.#store.del(address);\n\t\tawait this.#saveMeta();\n\t\treturn true;\n\t}\n\n\tasync #saveMeta(): Promise<void> {\n\t\tconst meta: StoredAccountMeta[] = this.getAccounts().map((a) => ({\n\t\t\taddress: a.address,\n\t\t\tlabel: a.label,\n\t\t}));\n\t\tawait this.#store.set(META_KEY, meta);\n\t}\n}\n"],"mappings":";;;;;AAgBA,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,WAAW;AAEjB,IAAa,yBAAb,cAA4C,kBAAkB;CAI7D;CAEA,YAAY,SAAmD;EAC9D,MAAM;YANO;cACE;EAMf,KAAKA,SAAS,IAAI,SACjB,SAAS,UAAU,iBACnB,SAAS,aAAa,kBACvB;CACD;CAEA,MAAM,aAA4B;EACjC,MAAM,aAAa,MAAM,KAAKA,OAAO,QAGnC;EACF,MAAM,OAA6B,MAAM,KAAKA,OAAO,IAAyB,QAAQ,KAAM,CAAC;EAE7F,MAAM,WAAW,CAAC;EAElB,KAAK,MAAM,CAAC,KAAK,UAAU,YAAY;GACtC,IAAI,QAAQ,UAAU;GAEtB,MAAM,UAAU;GAChB,IAAI;IACH,MAAM,WAAW;IACjB,MAAM,SAAS,gBAAgB,OAAO,QAAQ;IAC9C,MAAM,cAAc,KAAK,MAAM,MAAM,EAAE,YAAY,OAAO;IAC1D,SAAS,KAAK,oBAAoB,QAAQ,SAAS,aAAa,SAAS,SAAS,CAAC;GACpF,SAAS,OAAO;IACf,QAAQ,KAAK,uCAAuC,QAAQ,cAAc,KAAK;GAChF;EACD;EAEA,KAAK,mBAAmB,QAAQ;CACjC;CAEA,MAAM,cAAc,SAAyD;EAC5E,MAAM,SAAS,MAAM,gBAAgB,SAAS;EAC9C,MAAM,UAAU,OAAO,aAAa,CAAC,CAAC,aAAa;EAGnD,MAAM,iBAAiB,oBAAoB,QAAQ,SAFrC,SAAS,SAAS,KAAK,gBAAgB,CAEY;EAEjE,MAAM,KAAKA,OAAO,IAAI,SAAS,OAAO,OAAO,CAAC;EAC9C,KAAK,WAAW,cAAc;EAC9B,MAAM,KAAKC,UAAU;EAErB,OAAO;CACR;CAEA,MAAM,cAAc,SAAiB,OAAiC;EACrE,IAAI,CAAC,KAAK,eAAe,SAAS,KAAK,GAAG,OAAO;EACjD,MAAM,KAAKA,UAAU;EACrB,OAAO;CACR;CAEA,MAAM,cAAc,SAAmC;EACtD,IAAI,CAAC,KAAK,uBAAuB,OAAO,GAAG,OAAO;EAElD,MAAM,KAAKD,OAAO,IAAI,OAAO;EAC7B,MAAM,KAAKC,UAAU;EACrB,OAAO;CACR;CAEA,MAAMA,YAA2B;EAChC,MAAM,OAA4B,KAAK,YAAY,CAAC,CAAC,KAAK,OAAO;GAChE,SAAS,EAAE;GACX,OAAO,EAAE;EACV,EAAE;EACF,MAAM,KAAKD,OAAO,IAAI,UAAU,IAAI;CACrC;AACD"}
|
package/dist/bin/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { resolve, dirname } from 'node:path';\nimport { parseArgs, promisify } from 'node:util';\n\nimport { serve } from '@hono/node-server';\nimport { Hono } from 'hono';\nimport { cors } from 'hono/cors';\n\nconst execFileAsync = promisify(execFile);\n\nconst MIME_TYPES: Record<string, string> = {\n\t'.html': 'text/html; charset=utf-8',\n\t'.js': 'application/javascript',\n\t'.mjs': 'application/javascript',\n\t'.css': 'text/css',\n\t'.json': 'application/json',\n\t'.svg': 'image/svg+xml',\n\t'.png': 'image/png',\n\t'.ico': 'image/x-icon',\n\t'.woff': 'font/woff',\n\t'.woff2': 'font/woff2',\n};\n\nfunction findStandaloneDir(startDir: string): string | null {\n\tlet dir = startDir;\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst candidate = resolve(dir, 'standalone');\n\t\tif (existsSync(resolve(candidate, 'index.html'))) return candidate;\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn null;\n}\n\nfunction formatStartupMessage(options: {\n\twalletUrl: string;\n\tbaseUrl: string;\n\tadapters: string[];\n\thasSuiCli: boolean;\n\tbookmarkletCode: string;\n}): string {\n\tconst { walletUrl, baseUrl, adapters, hasSuiCli, bookmarkletCode } = options;\n\treturn `\n Dev Wallet running at ${walletUrl}\n Adapters: ${adapters.join(', ')}${!hasSuiCli ? '\\n (Install sui CLI to enable CLI signing)' : ''}\n\n To connect from your dApp:\n\n import { DevWalletClient } from '@mysten-incubation/dev-wallet/client';\n DevWalletClient.register({ origin: '${baseUrl}' });\n\n Or use the bookmarklet — drag from the Settings tab, or copy:\n\n ${bookmarkletCode}\n\n Or paste in the browser console:\n\n var s=document.createElement('script');s.src='${baseUrl}/bookmarklet.js';document.head.appendChild(s);\n\n Press Ctrl+C to stop.\n`;\n}\n\nasync function main() {\n\tconst { values } = parseArgs({\n\t\toptions: {\n\t\t\tport: { type: 'string', default: '5174' },\n\t\t\thelp: { type: 'boolean', short: 'h' },\n\t\t},\n\t\tallowPositionals: true,\n\t});\n\n\tif (values.help) {\n\t\tconsole.log(`\nUsage: dev-wallet serve [options]\n\nStart a dev wallet web app for dApp signing.\n\nOptions:\n --port <number> Port to serve on (default: 5174)\n -h, --help Show this help message\n\nThe wallet automatically detects available adapters:\n - In-Memory (Ed25519) — always available\n - WebCrypto (Passkey) — available in browsers with IndexedDB\n - CLI Signer — available when the sui CLI is on your PATH\n`);\n\t\tprocess.exit(0);\n\t}\n\n\tconst port = Number(values.port ?? '5174');\n\tif (!Number.isInteger(port) || port < 1 || port > 65535) {\n\t\tconsole.error('Error: --port must be an integer between 1 and 65535');\n\t\tprocess.exit(1);\n\t}\n\n\tlet hasSuiCli = false;\n\ttry {\n\t\tawait execFileAsync('sui', ['--version']);\n\t\thasSuiCli = true;\n\t} catch {\n\t\t// sui CLI not available — CLI adapter will not be enabled\n\t}\n\n\tconst scriptDir = dirname(new URL(import.meta.url).pathname);\n\tconst standaloneDir = findStandaloneDir(scriptDir);\n\n\tif (!standaloneDir) {\n\t\tconsole.error(\n\t\t\t'Standalone wallet app not found.\\nRun `pnpm turbo build --filter=@mysten-incubation/dev-wallet` first.',\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tlet indexHtml = await readFile(resolve(standaloneDir, 'index.html'), 'utf-8');\n\tif (hasSuiCli) {\n\t\tindexHtml = indexHtml.replace(\n\t\t\t'</head>',\n\t\t\t'<script>window.__DEV_WALLET_CLI__=true;</script></head>',\n\t\t);\n\t\tif (!indexHtml.includes('__DEV_WALLET_CLI__')) {\n\t\t\tconsole.warn('Warning: Failed to inject CLI flag into index.html');\n\t\t}\n\t}\n\n\tlet bookmarkletJs: string | null = null;\n\ttry {\n\t\tbookmarkletJs = await readFile(resolve(standaloneDir, 'bookmarklet.js'), 'utf-8');\n\t} catch {\n\t\t// bookmarklet not available\n\t}\n\n\tconst app = new Hono();\n\tlet cliToken: string | null = null;\n\n\tif (hasSuiCli) {\n\t\tconst { createCliSigningMiddleware } = await import('../server/cli-signing-middleware.js');\n\t\tconst result = createCliSigningMiddleware({ port });\n\t\tcliToken = result.token;\n\t\tapp.route('/', result.app);\n\t}\n\n\tapp.get('/bookmarklet.js', cors({ origin: '*' }), (c) => {\n\t\tif (!bookmarkletJs) {\n\t\t\treturn c.text('Bookmarklet not found', 404);\n\t\t}\n\t\tc.header('Cache-Control', 'no-cache');\n\t\treturn c.body(bookmarkletJs, { headers: { 'Content-Type': 'application/javascript' } });\n\t});\n\n\tapp.get('*', async (c) => {\n\t\tconst urlPath = decodeURIComponent(new URL(c.req.url).pathname);\n\n\t\tif (urlPath === '/' || urlPath === '/index.html') {\n\t\t\treturn c.html(indexHtml);\n\t\t}\n\n\t\tconst filePath = resolve(standaloneDir, urlPath.slice(1));\n\t\tif (!filePath.startsWith(standaloneDir)) {\n\t\t\treturn c.html(indexHtml);\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = await readFile(filePath);\n\t\t\tconst ext = filePath.slice(filePath.lastIndexOf('.'));\n\t\t\tconst contentType = MIME_TYPES[ext] || 'application/octet-stream';\n\t\t\treturn c.body(content, { headers: { 'Content-Type': contentType } });\n\t\t} catch {\n\t\t\treturn c.html(indexHtml);\n\t\t}\n\t});\n\n\tconst baseUrl = `http://localhost:${port}`;\n\n\tconst server = serve({ fetch: app.fetch, port }, () => {\n\t\tconst enabledAdapters = ['In-Memory (Ed25519)', 'WebCrypto (Passkey)'];\n\t\tif (hasSuiCli) {\n\t\t\tenabledAdapters.push('CLI Signer');\n\t\t}\n\n\t\tconst walletUrl = cliToken ? `${baseUrl}/?token=${cliToken}` : baseUrl;\n\t\tconst bookmarkletCode = `javascript:void(document.head.appendChild(Object.assign(document.createElement('script'),{src:'${baseUrl}/bookmarklet.js'})))`;\n\n\t\tconsole.log(\n\t\t\tformatStartupMessage({\n\t\t\t\twalletUrl,\n\t\t\t\tbaseUrl,\n\t\t\t\tadapters: enabledAdapters,\n\t\t\t\thasSuiCli,\n\t\t\t\tbookmarkletCode,\n\t\t\t}),\n\t\t);\n\t});\n\n\tfunction shutdown() {\n\t\tconsole.log('\\nShutting down...');\n\t\tserver.close(() => process.exit(0));\n\t\tsetTimeout(() => process.exit(1), 3000).unref();\n\t}\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n}\n\nmain().catch((error) => {\n\tconsole.error('Failed to start dev wallet:', error);\n\tprocess.exit(1);\n});\n"],"mappings":";;;;;;;;;;AAcA,MAAM,gBAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { resolve, dirname } from 'node:path';\nimport { parseArgs, promisify } from 'node:util';\n\nimport { serve } from '@hono/node-server';\nimport { Hono } from 'hono';\nimport { cors } from 'hono/cors';\n\nconst execFileAsync = promisify(execFile);\n\nconst MIME_TYPES: Record<string, string> = {\n\t'.html': 'text/html; charset=utf-8',\n\t'.js': 'application/javascript',\n\t'.mjs': 'application/javascript',\n\t'.css': 'text/css',\n\t'.json': 'application/json',\n\t'.svg': 'image/svg+xml',\n\t'.png': 'image/png',\n\t'.ico': 'image/x-icon',\n\t'.woff': 'font/woff',\n\t'.woff2': 'font/woff2',\n};\n\nfunction findStandaloneDir(startDir: string): string | null {\n\tlet dir = startDir;\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst candidate = resolve(dir, 'standalone');\n\t\tif (existsSync(resolve(candidate, 'index.html'))) return candidate;\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn null;\n}\n\nfunction formatStartupMessage(options: {\n\twalletUrl: string;\n\tbaseUrl: string;\n\tadapters: string[];\n\thasSuiCli: boolean;\n\tbookmarkletCode: string;\n}): string {\n\tconst { walletUrl, baseUrl, adapters, hasSuiCli, bookmarkletCode } = options;\n\treturn `\n Dev Wallet running at ${walletUrl}\n Adapters: ${adapters.join(', ')}${!hasSuiCli ? '\\n (Install sui CLI to enable CLI signing)' : ''}\n\n To connect from your dApp:\n\n import { DevWalletClient } from '@mysten-incubation/dev-wallet/client';\n DevWalletClient.register({ origin: '${baseUrl}' });\n\n Or use the bookmarklet — drag from the Settings tab, or copy:\n\n ${bookmarkletCode}\n\n Or paste in the browser console:\n\n var s=document.createElement('script');s.src='${baseUrl}/bookmarklet.js';document.head.appendChild(s);\n\n Press Ctrl+C to stop.\n`;\n}\n\nasync function main() {\n\tconst { values } = parseArgs({\n\t\toptions: {\n\t\t\tport: { type: 'string', default: '5174' },\n\t\t\thelp: { type: 'boolean', short: 'h' },\n\t\t},\n\t\tallowPositionals: true,\n\t});\n\n\tif (values.help) {\n\t\tconsole.log(`\nUsage: dev-wallet serve [options]\n\nStart a dev wallet web app for dApp signing.\n\nOptions:\n --port <number> Port to serve on (default: 5174)\n -h, --help Show this help message\n\nThe wallet automatically detects available adapters:\n - In-Memory (Ed25519) — always available\n - WebCrypto (Passkey) — available in browsers with IndexedDB\n - CLI Signer — available when the sui CLI is on your PATH\n`);\n\t\tprocess.exit(0);\n\t}\n\n\tconst port = Number(values.port ?? '5174');\n\tif (!Number.isInteger(port) || port < 1 || port > 65535) {\n\t\tconsole.error('Error: --port must be an integer between 1 and 65535');\n\t\tprocess.exit(1);\n\t}\n\n\tlet hasSuiCli = false;\n\ttry {\n\t\tawait execFileAsync('sui', ['--version']);\n\t\thasSuiCli = true;\n\t} catch {\n\t\t// sui CLI not available — CLI adapter will not be enabled\n\t}\n\n\tconst scriptDir = dirname(new URL(import.meta.url).pathname);\n\tconst standaloneDir = findStandaloneDir(scriptDir);\n\n\tif (!standaloneDir) {\n\t\tconsole.error(\n\t\t\t'Standalone wallet app not found.\\nRun `pnpm turbo build --filter=@mysten-incubation/dev-wallet` first.',\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tlet indexHtml = await readFile(resolve(standaloneDir, 'index.html'), 'utf-8');\n\tif (hasSuiCli) {\n\t\tindexHtml = indexHtml.replace(\n\t\t\t'</head>',\n\t\t\t'<script>window.__DEV_WALLET_CLI__=true;</script></head>',\n\t\t);\n\t\tif (!indexHtml.includes('__DEV_WALLET_CLI__')) {\n\t\t\tconsole.warn('Warning: Failed to inject CLI flag into index.html');\n\t\t}\n\t}\n\n\tlet bookmarkletJs: string | null = null;\n\ttry {\n\t\tbookmarkletJs = await readFile(resolve(standaloneDir, 'bookmarklet.js'), 'utf-8');\n\t} catch {\n\t\t// bookmarklet not available\n\t}\n\n\tconst app = new Hono();\n\tlet cliToken: string | null = null;\n\n\tif (hasSuiCli) {\n\t\tconst { createCliSigningMiddleware } = await import('../server/cli-signing-middleware.js');\n\t\tconst result = createCliSigningMiddleware({ port });\n\t\tcliToken = result.token;\n\t\tapp.route('/', result.app);\n\t}\n\n\tapp.get('/bookmarklet.js', cors({ origin: '*' }), (c) => {\n\t\tif (!bookmarkletJs) {\n\t\t\treturn c.text('Bookmarklet not found', 404);\n\t\t}\n\t\tc.header('Cache-Control', 'no-cache');\n\t\treturn c.body(bookmarkletJs, { headers: { 'Content-Type': 'application/javascript' } });\n\t});\n\n\tapp.get('*', async (c) => {\n\t\tconst urlPath = decodeURIComponent(new URL(c.req.url).pathname);\n\n\t\tif (urlPath === '/' || urlPath === '/index.html') {\n\t\t\treturn c.html(indexHtml);\n\t\t}\n\n\t\tconst filePath = resolve(standaloneDir, urlPath.slice(1));\n\t\tif (!filePath.startsWith(standaloneDir)) {\n\t\t\treturn c.html(indexHtml);\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = await readFile(filePath);\n\t\t\tconst ext = filePath.slice(filePath.lastIndexOf('.'));\n\t\t\tconst contentType = MIME_TYPES[ext] || 'application/octet-stream';\n\t\t\treturn c.body(content, { headers: { 'Content-Type': contentType } });\n\t\t} catch {\n\t\t\treturn c.html(indexHtml);\n\t\t}\n\t});\n\n\tconst baseUrl = `http://localhost:${port}`;\n\n\tconst server = serve({ fetch: app.fetch, port }, () => {\n\t\tconst enabledAdapters = ['In-Memory (Ed25519)', 'WebCrypto (Passkey)'];\n\t\tif (hasSuiCli) {\n\t\t\tenabledAdapters.push('CLI Signer');\n\t\t}\n\n\t\tconst walletUrl = cliToken ? `${baseUrl}/?token=${cliToken}` : baseUrl;\n\t\tconst bookmarkletCode = `javascript:void(document.head.appendChild(Object.assign(document.createElement('script'),{src:'${baseUrl}/bookmarklet.js'})))`;\n\n\t\tconsole.log(\n\t\t\tformatStartupMessage({\n\t\t\t\twalletUrl,\n\t\t\t\tbaseUrl,\n\t\t\t\tadapters: enabledAdapters,\n\t\t\t\thasSuiCli,\n\t\t\t\tbookmarkletCode,\n\t\t\t}),\n\t\t);\n\t});\n\n\tfunction shutdown() {\n\t\tconsole.log('\\nShutting down...');\n\t\tserver.close(() => process.exit(0));\n\t\tsetTimeout(() => process.exit(1), 3000).unref();\n\t}\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n}\n\nmain().catch((error) => {\n\tconsole.error('Failed to start dev wallet:', error);\n\tprocess.exit(1);\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-wallet-client.d.mts","names":[],"sources":["../../src/client/dev-wallet-client.ts"],"mappings":";;;;AA8CA
|
|
1
|
+
{"version":3,"file":"dev-wallet-client.d.mts","names":[],"sources":["../../src/client/dev-wallet-client.ts"],"mappings":";;;;AA8CA;;;;;;;;;;AAE2B;AAoB3B;;;;;;;iBAtBgB,0BAAA,CAA2B,OAAA,GAAU,sBAAsB;EAC1E,EAAA;EACA,UAAA;IAAgB,UAAA;EAAA;AAAA;;;;UAoBA,sBAAA;EAyDf;EAvDD,IAAA;EAyDC;EAvDD,IAAA,GAAO,UAAU;EAS4B;EAP7C,MAAA;AAAA;;;;;cAOY,eAAA,YAA2B,MAAA;EAAA;cAQ3B,OAAA,GAAU,sBAAA;EAAA,OASf,QAAA,CAAS,OAAA,GAAU,sBAAA;EAAA,IAMtB,OAAA;EAAA,IAIA,IAAA;EAAA,IAIA,IAAA;EAAA,IAIA,MAAA;EAAA,IAIA,QAAA,aAAqB,qBAAA;EAAA,IAIrB,QAAA,IAAY,sBAAA,GACf,qBAAA,GACA,yBAAA,GACA,WAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-wallet-client.mjs","names":["#name","#icon","#origin","#sessionKey","#events","#tryRestoreSession","#accounts","#connect","#on","#disconnect","#signPersonalMessage","#signTransaction","#signAndExecuteTransaction","#createChannel","#setSession","#setAccountsFromSession","#clearSession","#getSession"],"sources":["../../src/client/dev-wallet-client.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { fromBase64, toBase64 } from '@mysten/sui/utils';\nimport { mitt, type Emitter } from '@mysten/utils';\nimport type {\n\tStandardConnectFeature,\n\tStandardConnectMethod,\n\tStandardDisconnectFeature,\n\tStandardDisconnectMethod,\n\tStandardEventsFeature,\n\tStandardEventsOnMethod,\n\tSuiFeatures,\n\tSuiSignAndExecuteTransactionMethod,\n\tSuiSignPersonalMessageMethod,\n\tSuiSignTransactionMethod,\n\tWallet,\n\tWalletIcon,\n} from '@mysten/wallet-standard';\nimport { getWallets, ReadonlyWalletAccount, SUI_CHAINS } from '@mysten/wallet-standard';\nimport { DappPostMessageChannel, decodeJwtSession } from '@mysten/window-wallet-core';\n\nimport { DEFAULT_WALLET_ICON, type WalletEventsMap } from '../wallet/constants.js';\n\nconst DEFAULT_WALLET_NAME = 'Dev Wallet (Web)';\nconst DEFAULT_ORIGIN = 'http://localhost:5174';\n\n/**\n * Creates a wallet initializer that can be passed to `createDAppKit({ walletInitializers: [...] })`.\n *\n * This registers a {@link DevWalletClient} that communicates with a standalone\n * dev wallet server via PostMessage popups.\n *\n * @example\n * ```ts\n * import { createDAppKit } from '@mysten/dapp-kit-react';\n * import { devWalletClientInitializer } from '@mysten-incubation/dev-wallet/client';\n *\n * const dAppKit = createDAppKit({\n * networks: ['devnet'],\n * walletInitializers: [\n * devWalletClientInitializer({ origin: 'http://localhost:5174' }),\n * ],\n * });\n * ```\n */\nexport function devWalletClientInitializer(options?: DevWalletClientOptions): {\n\tid: string;\n\tinitialize(): { unregister: () => void };\n} {\n\treturn {\n\t\tid: 'dev-wallet-client-initializer',\n\t\tinitialize() {\n\t\t\tconst unregister = DevWalletClient.register(options);\n\t\t\treturn { unregister };\n\t\t},\n\t};\n}\n\nconst WALLET_FEATURES = [\n\t'sui:signTransaction',\n\t'sui:signAndExecuteTransaction',\n\t'sui:signPersonalMessage',\n] as const;\n\n/**\n * Options for creating a DevWalletClient.\n */\nexport interface DevWalletClientOptions {\n\t/** Display name for the wallet. Defaults to 'Dev Wallet (Web)'. */\n\tname?: string;\n\t/** Data URI icon for the wallet. */\n\ticon?: WalletIcon;\n\t/** Origin of the dev wallet web app. Defaults to 'http://localhost:5174'. */\n\torigin?: string;\n}\n\n/**\n * Wallet-standard wallet that communicates with a standalone DevWallet\n * web app via PostMessage popups (started via `npx @mysten-incubation/dev-wallet serve`).\n */\nexport class DevWalletClient implements Wallet {\n\treadonly #name: string;\n\treadonly #icon: WalletIcon;\n\treadonly #origin: string;\n\treadonly #sessionKey: string;\n\t#accounts: ReadonlyWalletAccount[] = [];\n\t#events: Emitter<WalletEventsMap>;\n\n\tconstructor(options?: DevWalletClientOptions) {\n\t\tthis.#name = options?.name ?? DEFAULT_WALLET_NAME;\n\t\tthis.#icon = options?.icon ?? DEFAULT_WALLET_ICON;\n\t\tthis.#origin = options?.origin ?? DEFAULT_ORIGIN;\n\t\tthis.#sessionKey = `dev-wallet:session:${this.#origin}`;\n\t\tthis.#events = mitt();\n\t\tthis.#tryRestoreSession();\n\t}\n\n\tstatic register(options?: DevWalletClientOptions): () => void {\n\t\tconst wallet = new DevWalletClient(options);\n\t\tconst wallets = getWallets();\n\t\treturn wallets.register(wallet);\n\t}\n\n\tget version() {\n\t\treturn '1.0.0' as const;\n\t}\n\n\tget name() {\n\t\treturn this.#name;\n\t}\n\n\tget icon() {\n\t\treturn this.#icon;\n\t}\n\n\tget chains() {\n\t\treturn SUI_CHAINS;\n\t}\n\n\tget accounts(): readonly ReadonlyWalletAccount[] {\n\t\treturn this.#accounts;\n\t}\n\n\tget features(): StandardConnectFeature &\n\t\tStandardEventsFeature &\n\t\tStandardDisconnectFeature &\n\t\tSuiFeatures {\n\t\treturn {\n\t\t\t'standard:connect': {\n\t\t\t\tversion: '1.0.0',\n\t\t\t\tconnect: this.#connect,\n\t\t\t},\n\t\t\t'standard:events': {\n\t\t\t\tversion: '1.0.0',\n\t\t\t\ton: this.#on,\n\t\t\t},\n\t\t\t'standard:disconnect': {\n\t\t\t\tversion: '1.0.0',\n\t\t\t\tdisconnect: this.#disconnect,\n\t\t\t},\n\t\t\t'sui:signPersonalMessage': {\n\t\t\t\tversion: '1.1.0',\n\t\t\t\tsignPersonalMessage: this.#signPersonalMessage,\n\t\t\t},\n\t\t\t'sui:signTransaction': {\n\t\t\t\tversion: '2.0.0',\n\t\t\t\tsignTransaction: this.#signTransaction,\n\t\t\t},\n\t\t\t'sui:signAndExecuteTransaction': {\n\t\t\t\tversion: '2.0.0',\n\t\t\t\tsignAndExecuteTransaction: this.#signAndExecuteTransaction,\n\t\t\t},\n\t\t};\n\t}\n\n\t#on: StandardEventsOnMethod = (event, listener) => {\n\t\tthis.#events.on(event, listener);\n\t\treturn () => this.#events.off(event, listener);\n\t};\n\n\t#connect: StandardConnectMethod = async () => {\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({ type: 'connect' });\n\n\t\tthis.#setSession(response.session);\n\t\tthis.#setAccountsFromSession(response.session);\n\n\t\treturn { accounts: this.accounts };\n\t};\n\n\t#disconnect: StandardDisconnectMethod = async () => {\n\t\tthis.#clearSession();\n\t\tthis.#accounts = [];\n\t\tthis.#events.emit('change', { accounts: this.#accounts });\n\t};\n\n\t#signPersonalMessage: SuiSignPersonalMessageMethod = async (input) => {\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({\n\t\t\ttype: 'sign-personal-message',\n\t\t\tmessage: toBase64(input.message),\n\t\t\taddress: input.account.address,\n\t\t\tchain: input.chain ?? input.account.chains[0] ?? 'sui:unknown',\n\t\t\tsession: this.#getSession(),\n\t\t});\n\n\t\treturn { bytes: response.bytes, signature: response.signature };\n\t};\n\n\t#signTransaction: SuiSignTransactionMethod = async (input) => {\n\t\tconst txJson = await input.transaction.toJSON();\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({\n\t\t\ttype: 'sign-transaction',\n\t\t\ttransaction: txJson,\n\t\t\taddress: input.account.address,\n\t\t\tchain: input.chain,\n\t\t\tsession: this.#getSession(),\n\t\t});\n\n\t\treturn { bytes: response.bytes, signature: response.signature };\n\t};\n\n\t#signAndExecuteTransaction: SuiSignAndExecuteTransactionMethod = async (input) => {\n\t\tconst txJson = await input.transaction.toJSON();\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({\n\t\t\ttype: 'sign-and-execute-transaction',\n\t\t\ttransaction: txJson,\n\t\t\taddress: input.account.address,\n\t\t\tchain: input.chain,\n\t\t\tsession: this.#getSession(),\n\t\t});\n\n\t\treturn {\n\t\t\tbytes: response.bytes,\n\t\t\tsignature: response.signature,\n\t\t\tdigest: response.digest,\n\t\t\teffects: response.effects,\n\t\t};\n\t};\n\n\t#createChannel(): DappPostMessageChannel {\n\t\treturn new DappPostMessageChannel({\n\t\t\tappName: this.#name,\n\t\t\thostOrigin: this.#origin,\n\t\t});\n\t}\n\n\t#getSession(): string {\n\t\tif (typeof localStorage === 'undefined') {\n\t\t\tthrow new Error('No active session. Call connect() first.');\n\t\t}\n\t\tconst session = localStorage.getItem(this.#sessionKey);\n\t\tif (!session) {\n\t\t\tthrow new Error('No active session. Call connect() first.');\n\t\t}\n\t\treturn session;\n\t}\n\n\t#setSession(session: string): void {\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.setItem(this.#sessionKey, session);\n\t\t}\n\t}\n\n\t#clearSession(): void {\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.removeItem(this.#sessionKey);\n\t\t}\n\t}\n\n\t#setAccountsFromSession(session: string): void {\n\t\tconst decoded = decodeJwtSession(session);\n\t\tthis.#accounts = decoded.payload.accounts.map(\n\t\t\t(account: { address: string; publicKey: string; label?: string }) =>\n\t\t\t\tnew ReadonlyWalletAccount({\n\t\t\t\t\taddress: account.address,\n\t\t\t\t\tpublicKey: account.publicKey ? fromBase64(account.publicKey) : new Uint8Array(0),\n\t\t\t\t\tchains: [...SUI_CHAINS],\n\t\t\t\t\tfeatures: [...WALLET_FEATURES],\n\t\t\t\t\tlabel: account.label,\n\t\t\t\t}),\n\t\t);\n\t\tthis.#events.emit('change', { accounts: this.#accounts });\n\t}\n\n\t#tryRestoreSession(): void {\n\t\tif (typeof localStorage === 'undefined') return;\n\t\tconst session = localStorage.getItem(this.#sessionKey);\n\t\tif (!session) return;\n\n\t\ttry {\n\t\t\tthis.#setAccountsFromSession(session);\n\t\t} catch {\n\t\t\tthis.#clearSession();\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dev-wallet-client.mjs","names":["#name","#icon","#origin","#sessionKey","#events","#tryRestoreSession","#accounts","#connect","#on","#disconnect","#signPersonalMessage","#signTransaction","#signAndExecuteTransaction","#createChannel","#setSession","#setAccountsFromSession","#clearSession","#getSession"],"sources":["../../src/client/dev-wallet-client.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { fromBase64, toBase64 } from '@mysten/sui/utils';\nimport { mitt, type Emitter } from '@mysten/utils';\nimport type {\n\tStandardConnectFeature,\n\tStandardConnectMethod,\n\tStandardDisconnectFeature,\n\tStandardDisconnectMethod,\n\tStandardEventsFeature,\n\tStandardEventsOnMethod,\n\tSuiFeatures,\n\tSuiSignAndExecuteTransactionMethod,\n\tSuiSignPersonalMessageMethod,\n\tSuiSignTransactionMethod,\n\tWallet,\n\tWalletIcon,\n} from '@mysten/wallet-standard';\nimport { getWallets, ReadonlyWalletAccount, SUI_CHAINS } from '@mysten/wallet-standard';\nimport { DappPostMessageChannel, decodeJwtSession } from '@mysten/window-wallet-core';\n\nimport { DEFAULT_WALLET_ICON, type WalletEventsMap } from '../wallet/constants.js';\n\nconst DEFAULT_WALLET_NAME = 'Dev Wallet (Web)';\nconst DEFAULT_ORIGIN = 'http://localhost:5174';\n\n/**\n * Creates a wallet initializer that can be passed to `createDAppKit({ walletInitializers: [...] })`.\n *\n * This registers a {@link DevWalletClient} that communicates with a standalone\n * dev wallet server via PostMessage popups.\n *\n * @example\n * ```ts\n * import { createDAppKit } from '@mysten/dapp-kit-react';\n * import { devWalletClientInitializer } from '@mysten-incubation/dev-wallet/client';\n *\n * const dAppKit = createDAppKit({\n * networks: ['devnet'],\n * walletInitializers: [\n * devWalletClientInitializer({ origin: 'http://localhost:5174' }),\n * ],\n * });\n * ```\n */\nexport function devWalletClientInitializer(options?: DevWalletClientOptions): {\n\tid: string;\n\tinitialize(): { unregister: () => void };\n} {\n\treturn {\n\t\tid: 'dev-wallet-client-initializer',\n\t\tinitialize() {\n\t\t\tconst unregister = DevWalletClient.register(options);\n\t\t\treturn { unregister };\n\t\t},\n\t};\n}\n\nconst WALLET_FEATURES = [\n\t'sui:signTransaction',\n\t'sui:signAndExecuteTransaction',\n\t'sui:signPersonalMessage',\n] as const;\n\n/**\n * Options for creating a DevWalletClient.\n */\nexport interface DevWalletClientOptions {\n\t/** Display name for the wallet. Defaults to 'Dev Wallet (Web)'. */\n\tname?: string;\n\t/** Data URI icon for the wallet. */\n\ticon?: WalletIcon;\n\t/** Origin of the dev wallet web app. Defaults to 'http://localhost:5174'. */\n\torigin?: string;\n}\n\n/**\n * Wallet-standard wallet that communicates with a standalone DevWallet\n * web app via PostMessage popups (started via `npx @mysten-incubation/dev-wallet serve`).\n */\nexport class DevWalletClient implements Wallet {\n\treadonly #name: string;\n\treadonly #icon: WalletIcon;\n\treadonly #origin: string;\n\treadonly #sessionKey: string;\n\t#accounts: ReadonlyWalletAccount[] = [];\n\t#events: Emitter<WalletEventsMap>;\n\n\tconstructor(options?: DevWalletClientOptions) {\n\t\tthis.#name = options?.name ?? DEFAULT_WALLET_NAME;\n\t\tthis.#icon = options?.icon ?? DEFAULT_WALLET_ICON;\n\t\tthis.#origin = options?.origin ?? DEFAULT_ORIGIN;\n\t\tthis.#sessionKey = `dev-wallet:session:${this.#origin}`;\n\t\tthis.#events = mitt();\n\t\tthis.#tryRestoreSession();\n\t}\n\n\tstatic register(options?: DevWalletClientOptions): () => void {\n\t\tconst wallet = new DevWalletClient(options);\n\t\tconst wallets = getWallets();\n\t\treturn wallets.register(wallet);\n\t}\n\n\tget version() {\n\t\treturn '1.0.0' as const;\n\t}\n\n\tget name() {\n\t\treturn this.#name;\n\t}\n\n\tget icon() {\n\t\treturn this.#icon;\n\t}\n\n\tget chains() {\n\t\treturn SUI_CHAINS;\n\t}\n\n\tget accounts(): readonly ReadonlyWalletAccount[] {\n\t\treturn this.#accounts;\n\t}\n\n\tget features(): StandardConnectFeature &\n\t\tStandardEventsFeature &\n\t\tStandardDisconnectFeature &\n\t\tSuiFeatures {\n\t\treturn {\n\t\t\t'standard:connect': {\n\t\t\t\tversion: '1.0.0',\n\t\t\t\tconnect: this.#connect,\n\t\t\t},\n\t\t\t'standard:events': {\n\t\t\t\tversion: '1.0.0',\n\t\t\t\ton: this.#on,\n\t\t\t},\n\t\t\t'standard:disconnect': {\n\t\t\t\tversion: '1.0.0',\n\t\t\t\tdisconnect: this.#disconnect,\n\t\t\t},\n\t\t\t'sui:signPersonalMessage': {\n\t\t\t\tversion: '1.1.0',\n\t\t\t\tsignPersonalMessage: this.#signPersonalMessage,\n\t\t\t},\n\t\t\t'sui:signTransaction': {\n\t\t\t\tversion: '2.0.0',\n\t\t\t\tsignTransaction: this.#signTransaction,\n\t\t\t},\n\t\t\t'sui:signAndExecuteTransaction': {\n\t\t\t\tversion: '2.0.0',\n\t\t\t\tsignAndExecuteTransaction: this.#signAndExecuteTransaction,\n\t\t\t},\n\t\t};\n\t}\n\n\t#on: StandardEventsOnMethod = (event, listener) => {\n\t\tthis.#events.on(event, listener);\n\t\treturn () => this.#events.off(event, listener);\n\t};\n\n\t#connect: StandardConnectMethod = async () => {\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({ type: 'connect' });\n\n\t\tthis.#setSession(response.session);\n\t\tthis.#setAccountsFromSession(response.session);\n\n\t\treturn { accounts: this.accounts };\n\t};\n\n\t#disconnect: StandardDisconnectMethod = async () => {\n\t\tthis.#clearSession();\n\t\tthis.#accounts = [];\n\t\tthis.#events.emit('change', { accounts: this.#accounts });\n\t};\n\n\t#signPersonalMessage: SuiSignPersonalMessageMethod = async (input) => {\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({\n\t\t\ttype: 'sign-personal-message',\n\t\t\tmessage: toBase64(input.message),\n\t\t\taddress: input.account.address,\n\t\t\tchain: input.chain ?? input.account.chains[0] ?? 'sui:unknown',\n\t\t\tsession: this.#getSession(),\n\t\t});\n\n\t\treturn { bytes: response.bytes, signature: response.signature };\n\t};\n\n\t#signTransaction: SuiSignTransactionMethod = async (input) => {\n\t\tconst txJson = await input.transaction.toJSON();\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({\n\t\t\ttype: 'sign-transaction',\n\t\t\ttransaction: txJson,\n\t\t\taddress: input.account.address,\n\t\t\tchain: input.chain,\n\t\t\tsession: this.#getSession(),\n\t\t});\n\n\t\treturn { bytes: response.bytes, signature: response.signature };\n\t};\n\n\t#signAndExecuteTransaction: SuiSignAndExecuteTransactionMethod = async (input) => {\n\t\tconst txJson = await input.transaction.toJSON();\n\t\tconst channel = this.#createChannel();\n\t\tconst response = await channel.send({\n\t\t\ttype: 'sign-and-execute-transaction',\n\t\t\ttransaction: txJson,\n\t\t\taddress: input.account.address,\n\t\t\tchain: input.chain,\n\t\t\tsession: this.#getSession(),\n\t\t});\n\n\t\treturn {\n\t\t\tbytes: response.bytes,\n\t\t\tsignature: response.signature,\n\t\t\tdigest: response.digest,\n\t\t\teffects: response.effects,\n\t\t};\n\t};\n\n\t#createChannel(): DappPostMessageChannel {\n\t\treturn new DappPostMessageChannel({\n\t\t\tappName: this.#name,\n\t\t\thostOrigin: this.#origin,\n\t\t});\n\t}\n\n\t#getSession(): string {\n\t\tif (typeof localStorage === 'undefined') {\n\t\t\tthrow new Error('No active session. Call connect() first.');\n\t\t}\n\t\tconst session = localStorage.getItem(this.#sessionKey);\n\t\tif (!session) {\n\t\t\tthrow new Error('No active session. Call connect() first.');\n\t\t}\n\t\treturn session;\n\t}\n\n\t#setSession(session: string): void {\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.setItem(this.#sessionKey, session);\n\t\t}\n\t}\n\n\t#clearSession(): void {\n\t\tif (typeof localStorage !== 'undefined') {\n\t\t\tlocalStorage.removeItem(this.#sessionKey);\n\t\t}\n\t}\n\n\t#setAccountsFromSession(session: string): void {\n\t\tconst decoded = decodeJwtSession(session);\n\t\tthis.#accounts = decoded.payload.accounts.map(\n\t\t\t(account: { address: string; publicKey: string; label?: string }) =>\n\t\t\t\tnew ReadonlyWalletAccount({\n\t\t\t\t\taddress: account.address,\n\t\t\t\t\tpublicKey: account.publicKey ? fromBase64(account.publicKey) : new Uint8Array(0),\n\t\t\t\t\tchains: [...SUI_CHAINS],\n\t\t\t\t\tfeatures: [...WALLET_FEATURES],\n\t\t\t\t\tlabel: account.label,\n\t\t\t\t}),\n\t\t);\n\t\tthis.#events.emit('change', { accounts: this.#accounts });\n\t}\n\n\t#tryRestoreSession(): void {\n\t\tif (typeof localStorage === 'undefined') return;\n\t\tconst session = localStorage.getItem(this.#sessionKey);\n\t\tif (!session) return;\n\n\t\ttry {\n\t\t\tthis.#setAccountsFromSession(session);\n\t\t} catch {\n\t\t\tthis.#clearSession();\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-handler.d.mts","names":[],"sources":["../../src/client/request-handler.ts"],"mappings":";;;;;;AAiBA;;;;UAAiB,oBAAA;EAChB,IAAA;EACA,OAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,IAAA,YAAgB,UAAA;EAMhB;;;;;EAAA,OAAA,CAAQ,OAAA;IAAY,iBAAA;EAAA,IAAiC,
|
|
1
|
+
{"version":3,"file":"request-handler.d.mts","names":[],"sources":["../../src/client/request-handler.ts"],"mappings":";;;;;;AAiBA;;;;UAAiB,oBAAA;EAChB,IAAA;EACA,OAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,IAAA,YAAgB,UAAA;EAMhB;;;;;EAAA,OAAA,CAAQ,OAAA;IAAY,iBAAA;EAAA,IAAiC,OAAO;EAK5C;EAHhB,MAAA,CAAO,MAAA;AAAA;AAAA,UAGS,oBAAA;EAIF;EAFd,QAAA,EAAU,aAAA;EAIuB;EAFjC,YAAA,EAAc,SAAA,GAAY,UAAA;EAEwB;EAAlD,SAAA,IAAa,OAAA,aAAoB,iBAAA;EAJvB;EAMV,IAAA;AAAA;AAAA,iBAGe,kBAAA,CAAmB,OAAA,EAAS,oBAAA,GAAuB,oBAAoB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-handler.mjs","names":[],"sources":["../../src/client/request-handler.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ClientWithCoreApi } from '@mysten/sui/client';\nimport { fromBase64, toBase64 } from '@mysten/sui/utils';\nimport { createJwtSession, WalletPostMessageChannel } from '@mysten/window-wallet-core';\n\nimport type { SignerAdapter } from '../types.js';\nimport { getNetworkFromChain } from '../wallet/constants.js';\nimport { executeSigning } from '../wallet/signing.js';\n\n/**\n * A parsed wallet request with methods to approve or reject it.\n *\n * This is different from `PendingSigningRequest` (in dev-wallet.ts) — this interface\n * includes `approve()`/`reject()` methods and is specific to the standalone popup flow.\n */\nexport interface PendingWalletRequest {\n\ttype: 'connect' | 'sign-transaction' | 'sign-and-execute-transaction' | 'sign-personal-message';\n\tappName: string;\n\tappUrl: string;\n\taddress?: string;\n\tchain?: string;\n\tdata?: string | Uint8Array;\n\t/**\n\t * Approve the request.\n\t * For connect: creates a session with the selected accounts (or all if none specified).\n\t * For signing: signs with the adapter.\n\t */\n\tapprove(options?: { selectedAddresses?: string[] }): Promise<void>;\n\t/** Reject the request with an optional reason. */\n\treject(reason?: string): void;\n}\n\nexport interface HandleRequestOptions {\n\t/** The signer adapters providing accounts and signing capability. */\n\tadapters: SignerAdapter[];\n\t/** JWT secret key for session creation. */\n\tjwtSecretKey: CryptoKey | Uint8Array;\n\t/** Resolve a client for a given network name (needed for signAndExecute). */\n\tgetClient?: (network: string) => ClientWithCoreApi | undefined;\n\t/** URL hash containing the encoded request. Defaults to window.location.hash. */\n\thash?: string;\n}\n\nexport function parseWalletRequest(options: HandleRequestOptions): PendingWalletRequest {\n\tif (!options.hash && typeof window === 'undefined') {\n\t\tthrow new Error(\n\t\t\t'parseWalletRequest requires either options.hash or a browser environment with window.location',\n\t\t);\n\t}\n\tconst hash = options.hash ?? window.location.hash.slice(1);\n\tconst channel = WalletPostMessageChannel.fromUrlHash(hash);\n\tconst requestData = channel.getRequestData();\n\tconst payload = requestData.payload;\n\n\tif (payload.type === 'connect') {\n\t\treturn {\n\t\t\ttype: 'connect',\n\t\t\tappName: requestData.appName,\n\t\t\tappUrl: requestData.appUrl,\n\t\t\tasync approve(approveOptions?: { selectedAddresses?: string[] }) {\n\t\t\t\tconst allAccounts = options.adapters.flatMap((adapter) =>\n\t\t\t\t\tadapter.getAccounts().map((a) => ({\n\t\t\t\t\t\taddress: a.address,\n\t\t\t\t\t\tpublicKey: toBase64(a.signer.getPublicKey().toSuiBytes()),\n\t\t\t\t\t\tlabel: a.label,\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tconst selected = approveOptions?.selectedAddresses;\n\t\t\t\tconst accounts = selected\n\t\t\t\t\t? allAccounts.filter((a) => selected.includes(a.address))\n\t\t\t\t\t: allAccounts;\n\n\t\t\t\tconst session = await createJwtSession(\n\t\t\t\t\t{ accounts },\n\t\t\t\t\t{\n\t\t\t\t\t\tsecretKey: options.jwtSecretKey,\n\t\t\t\t\t\texpirationTime: '7d',\n\t\t\t\t\t\tissuer: 'dev-wallet',\n\t\t\t\t\t\taudience: new URL(requestData.appUrl).origin,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'resolve',\n\t\t\t\t\tdata: { type: 'connect', session },\n\t\t\t\t});\n\t\t\t},\n\t\t\treject(reason?: string) {\n\t\t\t\tchannel.sendMessage({ type: 'reject', reason });\n\t\t\t},\n\t\t};\n\t}\n\n\tconst messageData =\n\t\tpayload.type === 'sign-personal-message' ? fromBase64(payload.message) : payload.transaction;\n\n\treturn {\n\t\ttype: payload.type,\n\t\tappName: requestData.appName,\n\t\tappUrl: requestData.appUrl,\n\t\taddress: payload.address,\n\t\tchain: payload.chain,\n\t\tdata: messageData,\n\t\tasync approve() {\n\t\t\t// Verify JWT session before signing — ensures the dApp was previously\n\t\t\t// authorized for this account via a connect flow\n\t\t\ttry {\n\t\t\t\tawait channel.verifyJwtSession(options.jwtSecretKey);\n\t\t\t} catch (error) {\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'reject',\n\t\t\t\t\treason: `Session verification failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet account;\n\t\t\tfor (const adapter of options.adapters) {\n\t\t\t\taccount = adapter.getAccount(payload.address);\n\t\t\t\tif (account) break;\n\t\t\t}\n\t\t\tif (!account) {\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'reject',\n\t\t\t\t\treason: `Account ${payload.address} not found`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst network = payload.chain ? getNetworkFromChain(payload.chain) : undefined;\n\t\t\t\tconst client = network ? options.getClient?.(network) : undefined;\n\t\t\t\tconst result = await executeSigning({\n\t\t\t\t\ttype: payload.type,\n\t\t\t\t\tsigner: account.signer,\n\t\t\t\t\tdata: messageData,\n\t\t\t\t\tclient,\n\t\t\t\t});\n\t\t\t\t// effects must be a string in the PostMessage protocol\n\t\t\t\tconst data =\n\t\t\t\t\tresult.type === 'sign-and-execute-transaction'\n\t\t\t\t\t\t? { ...result, effects: result.effects ?? '' }\n\t\t\t\t\t\t: result;\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'resolve',\n\t\t\t\t\tdata,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'reject',\n\t\t\t\t\treason: error instanceof Error ? error.message : String(error),\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\treject(reason?: string) {\n\t\t\tchannel.sendMessage({ type: 'reject', reason });\n\t\t},\n\t};\n}\n"],"mappings":";;;;;AA6CA,SAAgB,mBAAmB,SAAqD;
|
|
1
|
+
{"version":3,"file":"request-handler.mjs","names":[],"sources":["../../src/client/request-handler.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ClientWithCoreApi } from '@mysten/sui/client';\nimport { fromBase64, toBase64 } from '@mysten/sui/utils';\nimport { createJwtSession, WalletPostMessageChannel } from '@mysten/window-wallet-core';\n\nimport type { SignerAdapter } from '../types.js';\nimport { getNetworkFromChain } from '../wallet/constants.js';\nimport { executeSigning } from '../wallet/signing.js';\n\n/**\n * A parsed wallet request with methods to approve or reject it.\n *\n * This is different from `PendingSigningRequest` (in dev-wallet.ts) — this interface\n * includes `approve()`/`reject()` methods and is specific to the standalone popup flow.\n */\nexport interface PendingWalletRequest {\n\ttype: 'connect' | 'sign-transaction' | 'sign-and-execute-transaction' | 'sign-personal-message';\n\tappName: string;\n\tappUrl: string;\n\taddress?: string;\n\tchain?: string;\n\tdata?: string | Uint8Array;\n\t/**\n\t * Approve the request.\n\t * For connect: creates a session with the selected accounts (or all if none specified).\n\t * For signing: signs with the adapter.\n\t */\n\tapprove(options?: { selectedAddresses?: string[] }): Promise<void>;\n\t/** Reject the request with an optional reason. */\n\treject(reason?: string): void;\n}\n\nexport interface HandleRequestOptions {\n\t/** The signer adapters providing accounts and signing capability. */\n\tadapters: SignerAdapter[];\n\t/** JWT secret key for session creation. */\n\tjwtSecretKey: CryptoKey | Uint8Array;\n\t/** Resolve a client for a given network name (needed for signAndExecute). */\n\tgetClient?: (network: string) => ClientWithCoreApi | undefined;\n\t/** URL hash containing the encoded request. Defaults to window.location.hash. */\n\thash?: string;\n}\n\nexport function parseWalletRequest(options: HandleRequestOptions): PendingWalletRequest {\n\tif (!options.hash && typeof window === 'undefined') {\n\t\tthrow new Error(\n\t\t\t'parseWalletRequest requires either options.hash or a browser environment with window.location',\n\t\t);\n\t}\n\tconst hash = options.hash ?? window.location.hash.slice(1);\n\tconst channel = WalletPostMessageChannel.fromUrlHash(hash);\n\tconst requestData = channel.getRequestData();\n\tconst payload = requestData.payload;\n\n\tif (payload.type === 'connect') {\n\t\treturn {\n\t\t\ttype: 'connect',\n\t\t\tappName: requestData.appName,\n\t\t\tappUrl: requestData.appUrl,\n\t\t\tasync approve(approveOptions?: { selectedAddresses?: string[] }) {\n\t\t\t\tconst allAccounts = options.adapters.flatMap((adapter) =>\n\t\t\t\t\tadapter.getAccounts().map((a) => ({\n\t\t\t\t\t\taddress: a.address,\n\t\t\t\t\t\tpublicKey: toBase64(a.signer.getPublicKey().toSuiBytes()),\n\t\t\t\t\t\tlabel: a.label,\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tconst selected = approveOptions?.selectedAddresses;\n\t\t\t\tconst accounts = selected\n\t\t\t\t\t? allAccounts.filter((a) => selected.includes(a.address))\n\t\t\t\t\t: allAccounts;\n\n\t\t\t\tconst session = await createJwtSession(\n\t\t\t\t\t{ accounts },\n\t\t\t\t\t{\n\t\t\t\t\t\tsecretKey: options.jwtSecretKey,\n\t\t\t\t\t\texpirationTime: '7d',\n\t\t\t\t\t\tissuer: 'dev-wallet',\n\t\t\t\t\t\taudience: new URL(requestData.appUrl).origin,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'resolve',\n\t\t\t\t\tdata: { type: 'connect', session },\n\t\t\t\t});\n\t\t\t},\n\t\t\treject(reason?: string) {\n\t\t\t\tchannel.sendMessage({ type: 'reject', reason });\n\t\t\t},\n\t\t};\n\t}\n\n\tconst messageData =\n\t\tpayload.type === 'sign-personal-message' ? fromBase64(payload.message) : payload.transaction;\n\n\treturn {\n\t\ttype: payload.type,\n\t\tappName: requestData.appName,\n\t\tappUrl: requestData.appUrl,\n\t\taddress: payload.address,\n\t\tchain: payload.chain,\n\t\tdata: messageData,\n\t\tasync approve() {\n\t\t\t// Verify JWT session before signing — ensures the dApp was previously\n\t\t\t// authorized for this account via a connect flow\n\t\t\ttry {\n\t\t\t\tawait channel.verifyJwtSession(options.jwtSecretKey);\n\t\t\t} catch (error) {\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'reject',\n\t\t\t\t\treason: `Session verification failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet account;\n\t\t\tfor (const adapter of options.adapters) {\n\t\t\t\taccount = adapter.getAccount(payload.address);\n\t\t\t\tif (account) break;\n\t\t\t}\n\t\t\tif (!account) {\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'reject',\n\t\t\t\t\treason: `Account ${payload.address} not found`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst network = payload.chain ? getNetworkFromChain(payload.chain) : undefined;\n\t\t\t\tconst client = network ? options.getClient?.(network) : undefined;\n\t\t\t\tconst result = await executeSigning({\n\t\t\t\t\ttype: payload.type,\n\t\t\t\t\tsigner: account.signer,\n\t\t\t\t\tdata: messageData,\n\t\t\t\t\tclient,\n\t\t\t\t});\n\t\t\t\t// effects must be a string in the PostMessage protocol\n\t\t\t\tconst data =\n\t\t\t\t\tresult.type === 'sign-and-execute-transaction'\n\t\t\t\t\t\t? { ...result, effects: result.effects ?? '' }\n\t\t\t\t\t\t: result;\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'resolve',\n\t\t\t\t\tdata,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tchannel.sendMessage({\n\t\t\t\t\ttype: 'reject',\n\t\t\t\t\treason: error instanceof Error ? error.message : String(error),\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\treject(reason?: string) {\n\t\t\tchannel.sendMessage({ type: 'reject', reason });\n\t\t},\n\t};\n}\n"],"mappings":";;;;;AA6CA,SAAgB,mBAAmB,SAAqD;CACvF,IAAI,CAAC,QAAQ,QAAQ,OAAO,WAAW,aACtC,MAAM,IAAI,MACT,+FACD;CAED,MAAM,OAAO,QAAQ,QAAQ,OAAO,SAAS,KAAK,MAAM,CAAC;CACzD,MAAM,UAAU,yBAAyB,YAAY,IAAI;CACzD,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,UAAU,YAAY;CAE5B,IAAI,QAAQ,SAAS,WACpB,OAAO;EACN,MAAM;EACN,SAAS,YAAY;EACrB,QAAQ,YAAY;EACpB,MAAM,QAAQ,gBAAmD;GAChE,MAAM,cAAc,QAAQ,SAAS,SAAS,YAC7C,QAAQ,YAAY,CAAC,CAAC,KAAK,OAAO;IACjC,SAAS,EAAE;IACX,WAAW,SAAS,EAAE,OAAO,aAAa,CAAC,CAAC,WAAW,CAAC;IACxD,OAAO,EAAE;GACV,EAAE,CACH;GACA,MAAM,WAAW,gBAAgB;GAKjC,MAAM,UAAU,MAAM,iBACrB,EAAE,UALc,WACd,YAAY,QAAQ,MAAM,SAAS,SAAS,EAAE,OAAO,CAAC,IACtD,YAGS,GACX;IACC,WAAW,QAAQ;IACnB,gBAAgB;IAChB,QAAQ;IACR,UAAU,IAAI,IAAI,YAAY,MAAM,CAAC,CAAC;GACvC,CACD;GAEA,QAAQ,YAAY;IACnB,MAAM;IACN,MAAM;KAAE,MAAM;KAAW;IAAQ;GAClC,CAAC;EACF;EACA,OAAO,QAAiB;GACvB,QAAQ,YAAY;IAAE,MAAM;IAAU;GAAO,CAAC;EAC/C;CACD;CAGD,MAAM,cACL,QAAQ,SAAS,0BAA0B,WAAW,QAAQ,OAAO,IAAI,QAAQ;CAElF,OAAO;EACN,MAAM,QAAQ;EACd,SAAS,YAAY;EACrB,QAAQ,YAAY;EACpB,SAAS,QAAQ;EACjB,OAAO,QAAQ;EACf,MAAM;EACN,MAAM,UAAU;GAGf,IAAI;IACH,MAAM,QAAQ,iBAAiB,QAAQ,YAAY;GACpD,SAAS,OAAO;IACf,QAAQ,YAAY;KACnB,MAAM;KACN,QAAQ,gCAAgC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC9F,CAAC;IACD;GACD;GAEA,IAAI;GACJ,KAAK,MAAM,WAAW,QAAQ,UAAU;IACvC,UAAU,QAAQ,WAAW,QAAQ,OAAO;IAC5C,IAAI,SAAS;GACd;GACA,IAAI,CAAC,SAAS;IACb,QAAQ,YAAY;KACnB,MAAM;KACN,QAAQ,WAAW,QAAQ,QAAQ;IACpC,CAAC;IACD;GACD;GAEA,IAAI;IACH,MAAM,UAAU,QAAQ,QAAQ,oBAAoB,QAAQ,KAAK,IAAI;IACrE,MAAM,SAAS,UAAU,QAAQ,YAAY,OAAO,IAAI;IACxD,MAAM,SAAS,MAAM,eAAe;KACnC,MAAM,QAAQ;KACd,QAAQ,QAAQ;KAChB,MAAM;KACN;IACD,CAAC;IAED,MAAM,OACL,OAAO,SAAS,iCACb;KAAE,GAAG;KAAQ,SAAS,OAAO,WAAW;IAAG,IAC3C;IACJ,QAAQ,YAAY;KACnB,MAAM;KACN;IACD,CAAC;GACF,SAAS,OAAO;IACf,QAAQ,YAAY;KACnB,MAAM;KACN,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC9D,CAAC;GACF;EACD;EACA,OAAO,QAAiB;GACvB,QAAQ,YAAY;IAAE,MAAM;IAAU;GAAO,CAAC;EAC/C;CACD;AACD"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CreateAccountOptions, ImportAccountOptions, ManagedAccount, SignerAdapter } from "./types.mjs";
|
|
2
2
|
import { SigningResult } from "./wallet/signing.mjs";
|
|
3
3
|
import { AutoApprovePolicy, DEFAULT_NETWORK_URLS, DevWallet, DevWalletConfig, PendingConnectRequest, PendingSigningRequest } from "./wallet/dev-wallet.mjs";
|
|
4
|
+
import { MountAndRegisterDevWalletOptions, MountAndRegisterDevWalletResult, mountAndRegisterDevWallet } from "./wallet/mount-and-register.mjs";
|
|
4
5
|
import { DevWalletInitializerConfig, devWalletInitializer } from "./wallet/initializer.mjs";
|
|
5
|
-
export { type AutoApprovePolicy, type CreateAccountOptions, DEFAULT_NETWORK_URLS, DevWallet, type DevWalletConfig, type DevWalletInitializerConfig, type ImportAccountOptions, type ManagedAccount, type PendingConnectRequest, type PendingSigningRequest, type SignerAdapter, type SigningResult, devWalletInitializer };
|
|
6
|
+
export { type AutoApprovePolicy, type CreateAccountOptions, DEFAULT_NETWORK_URLS, DevWallet, type DevWalletConfig, type DevWalletInitializerConfig, type ImportAccountOptions, type ManagedAccount, type MountAndRegisterDevWalletOptions, type MountAndRegisterDevWalletResult, type PendingConnectRequest, type PendingSigningRequest, type SignerAdapter, type SigningResult, devWalletInitializer, mountAndRegisterDevWallet };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { DEFAULT_NETWORK_URLS, DevWallet } from "./wallet/dev-wallet.mjs";
|
|
2
|
+
import { mountAndRegisterDevWallet } from "./wallet/mount-and-register.mjs";
|
|
2
3
|
import { devWalletInitializer } from "./wallet/initializer.mjs";
|
|
3
|
-
export { DEFAULT_NETWORK_URLS, DevWallet, devWalletInitializer };
|
|
4
|
+
export { DEFAULT_NETWORK_URLS, DevWallet, devWalletInitializer, mountAndRegisterDevWallet };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AutoApprovePolicy, DevWallet } from "../wallet/dev-wallet.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/inject/index.d.ts
|
|
4
|
+
/** Shape of a single entry in the generated `accounts` map
|
|
5
|
+
* (`generated-extras/accounts.ts`). Only `address` is consumed here. */
|
|
6
|
+
interface DevstackAccountInfo {
|
|
7
|
+
readonly address: string;
|
|
8
|
+
readonly name?: string;
|
|
9
|
+
}
|
|
10
|
+
interface RegisterDevstackDevWalletConfig {
|
|
11
|
+
/** Wallet-app origin (`devWallet.walletUrl`). */
|
|
12
|
+
readonly serverOrigin: string;
|
|
13
|
+
/** Bearer token (`parseDevstackToken(devWallet.pairUrl)`), or null. */
|
|
14
|
+
readonly token?: string | null;
|
|
15
|
+
/** Generated name→account map (`accounts` from `generated-extras/accounts.ts`). */
|
|
16
|
+
readonly accounts: Readonly<Record<string, DevstackAccountInfo>>;
|
|
17
|
+
/** RPC endpoint the wallet uses to execute `signAndExecuteTransaction`
|
|
18
|
+
* (and simulate). MUST be the SAME routed RPC the app's dApp Kit client
|
|
19
|
+
* uses (`config.networks[config.network].rpc`) — a raw `127.0.0.1:9000`
|
|
20
|
+
* is CORS-blocked from the routed page origin. When omitted the wallet
|
|
21
|
+
* falls back to localnet defaults (only correct for non-routed setups). */
|
|
22
|
+
readonly rpcUrl?: string;
|
|
23
|
+
/** Network name the wallet's accounts are scoped to (e.g. `'localnet'`
|
|
24
|
+
* from `devWallet.network`). The wallet advertises the wallet-standard
|
|
25
|
+
* chain `sui:<network>` derived from it; defaults to `localnet`. */
|
|
26
|
+
readonly network?: string;
|
|
27
|
+
/** Auto-approve all signing requests (headless e2e). Defaults to false. */
|
|
28
|
+
readonly autoApprove?: AutoApprovePolicy;
|
|
29
|
+
/** Mount the floating wallet drawer UI. Defaults to true. */
|
|
30
|
+
readonly mountUI?: boolean;
|
|
31
|
+
/** Wallet display name. Defaults to `'Devstack'`. */
|
|
32
|
+
readonly name?: string;
|
|
33
|
+
}
|
|
34
|
+
interface RegisterDevstackDevWalletResult {
|
|
35
|
+
readonly wallet: DevWallet;
|
|
36
|
+
/** Unregister the wallet, unmount the UI, and tear down the adapter. */
|
|
37
|
+
readonly dispose: () => void;
|
|
38
|
+
}
|
|
39
|
+
/** Global marker so tests / the plugin can assert injection happened. */
|
|
40
|
+
declare global {
|
|
41
|
+
var __DEV_WALLET_INJECTED__: boolean | undefined;
|
|
42
|
+
/** In-flight (or settled) registration promise. Published BEFORE the first
|
|
43
|
+
* `await` so concurrent evaluations (HMR / double import) coalesce onto a
|
|
44
|
+
* single registration instead of each constructing + registering + mounting
|
|
45
|
+
* their own wallet. See `registerDevstackDevWallet`. */
|
|
46
|
+
var __devstackDevWalletPromise__: Promise<RegisterDevstackDevWalletResult> | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Construct + register the devstack dev wallet on the current page and wire
|
|
50
|
+
* the Playwright `connectAs` slot. Idempotent: a second call is a no-op and
|
|
51
|
+
* returns the existing instance.
|
|
52
|
+
*
|
|
53
|
+
* Idempotency is enforced SYNCHRONOUSLY: an in-flight registration promise is
|
|
54
|
+
* published on `globalThis.__devstackDevWalletPromise__` before the first
|
|
55
|
+
* `await`, so two evaluations that race in before the first one finishes both
|
|
56
|
+
* resolve to the SAME wallet instead of double-registering.
|
|
57
|
+
*/
|
|
58
|
+
declare function registerDevstackDevWallet(config: RegisterDevstackDevWalletConfig): Promise<RegisterDevstackDevWalletResult>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { DevstackAccountInfo, RegisterDevstackDevWalletConfig, RegisterDevstackDevWalletResult, registerDevstackDevWallet };
|
|
61
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/inject/index.ts"],"mappings":";;;;;UA6BiB,mBAAA;EAAA,SACP,OAAA;EAAA,SACA,IAAI;AAAA;AAAA,UAGG,+BAAA;EAAA;EAAA,SAEP,YAAA;;WAEA,KAAA;EAEmB;EAAA,SAAnB,QAAA,EAAU,QAAA,CAAS,MAAA,SAAe,mBAAA;EAYpB;;;;;EAAA,SANd,MAAA;EANU;;;EAAA,SAUV,OAAA;EAAA;EAAA,SAEA,WAAA,GAAc,iBAAA;EAAA;EAAA,SAEd,OAAA;EAEA;EAAA,SAAA,IAAA;AAAA;AAAA,UAGO,+BAAA;EAAA,SACP,MAAA,EAAQ,SAAS;;WAEjB,OAAA;AAAA;;QAIF,MAAA;EAAA,IAEH,uBAAA;EANY;AAChB;;;EADgB,IAYZ,4BAAA,EAA8B,OAAO,CAAC,+BAAA;AAAA;;;;;;;AAA4C;AAavF;;;iBAAgB,yBAAA,CACf,MAAA,EAAQ,+BAAA,GACN,OAAA,CAAQ,+BAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { mountAndRegisterDevWallet } from "../wallet/mount-and-register.mjs";
|
|
2
|
+
import { DevstackSignerAdapter } from "../adapters/devstack-adapter.mjs";
|
|
3
|
+
import { WebCryptoSignerAdapter } from "../adapters/webcrypto-adapter.mjs";
|
|
4
|
+
//#region src/inject/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Construct + register the devstack dev wallet on the current page and wire
|
|
7
|
+
* the Playwright `connectAs` slot. Idempotent: a second call is a no-op and
|
|
8
|
+
* returns the existing instance.
|
|
9
|
+
*
|
|
10
|
+
* Idempotency is enforced SYNCHRONOUSLY: an in-flight registration promise is
|
|
11
|
+
* published on `globalThis.__devstackDevWalletPromise__` before the first
|
|
12
|
+
* `await`, so two evaluations that race in before the first one finishes both
|
|
13
|
+
* resolve to the SAME wallet instead of double-registering.
|
|
14
|
+
*/
|
|
15
|
+
function registerDevstackDevWallet(config) {
|
|
16
|
+
const g = globalThis;
|
|
17
|
+
if (g.__devstackDevWallet__ !== void 0) return Promise.resolve(g.__devstackDevWallet__);
|
|
18
|
+
if (g.__devstackDevWalletPromise__ !== void 0) return g.__devstackDevWalletPromise__;
|
|
19
|
+
const promise = registerDevstackDevWalletImpl(config);
|
|
20
|
+
g.__devstackDevWalletPromise__ = promise;
|
|
21
|
+
promise.catch(() => {
|
|
22
|
+
if (g.__devstackDevWalletPromise__ === promise) g.__devstackDevWalletPromise__ = void 0;
|
|
23
|
+
});
|
|
24
|
+
return promise;
|
|
25
|
+
}
|
|
26
|
+
async function registerDevstackDevWalletImpl(config) {
|
|
27
|
+
const { mountUI = true, autoApprove = false } = config;
|
|
28
|
+
globalThis.__DEV_WALLET_INJECTED__ = true;
|
|
29
|
+
const adapter = new DevstackSignerAdapter({
|
|
30
|
+
serverOrigin: config.serverOrigin,
|
|
31
|
+
token: config.token ?? null,
|
|
32
|
+
name: config.name ?? "Devstack"
|
|
33
|
+
});
|
|
34
|
+
const rpcUrl = config.rpcUrl ?? "http://127.0.0.1:9000";
|
|
35
|
+
const activeNetwork = config.network ?? "localnet";
|
|
36
|
+
const networks = { [activeNetwork]: rpcUrl };
|
|
37
|
+
const { wallet, dispose: disposeWallet } = await mountAndRegisterDevWallet({
|
|
38
|
+
adapters: [adapter, new WebCryptoSignerAdapter()],
|
|
39
|
+
name: config.name ?? "Devstack",
|
|
40
|
+
autoApprove,
|
|
41
|
+
autoConnect: Boolean(autoApprove),
|
|
42
|
+
networks,
|
|
43
|
+
activeNetwork,
|
|
44
|
+
mountUI
|
|
45
|
+
});
|
|
46
|
+
const result = {
|
|
47
|
+
wallet,
|
|
48
|
+
dispose() {
|
|
49
|
+
disposeWallet();
|
|
50
|
+
globalThis.__DEV_WALLET_INJECTED__ = false;
|
|
51
|
+
delete globalThis.__devstackDevWallet__;
|
|
52
|
+
delete globalThis.__devstackDevWalletPromise__;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
globalThis.__devstackDevWallet__ = result;
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { registerDevstackDevWallet };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/inject/index.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n//\n// Page-register entry for the devstack dev wallet.\n//\n// This is the single function the devstack Vite plugin injects into a dev\n// page. It builds the token-based `DevstackSignerAdapter` (headless — signs\n// over HTTP, no popup) + the routed-RPC network map, then hands those to the\n// shared `mountAndRegisterDevWallet` core helper, which constructs the\n// `DevWallet`, registers it via wallet-standard (so dApp Kit auto-discovers\n// it), and mounts the floating wallet UI. The ONLY logic that lives here is\n// the devstack-integration glue: the adapter-from-config and the routed-RPC\n// network map.\n//\n// The wallet does NOT pre-connect or seed dApp Kit storage: a fresh page\n// loads disconnected, dApp Kit's own `autoConnect` only re-connects a genuine\n// prior session, and the Playwright `connectAs` helper performs an explicit\n// connection through dApp Kit's public API. That test bridge is registered\n// app-side via `@mysten-incubation/devstack/dapp-kit`'s\n// `registerDAppKitForTesting(dAppKit)` (DEV-only) — it needs the app's dApp\n// Kit instance, which the wallet has no reference to.\n\nimport type { AutoApprovePolicy, DevWallet } from '../wallet/dev-wallet.js';\nimport { mountAndRegisterDevWallet } from '../wallet/mount-and-register.js';\nimport { DevstackSignerAdapter } from '../adapters/devstack-adapter.js';\nimport { WebCryptoSignerAdapter } from '../adapters/webcrypto-adapter.js';\n\n/** Shape of a single entry in the generated `accounts` map\n * (`generated-extras/accounts.ts`). Only `address` is consumed here. */\nexport interface DevstackAccountInfo {\n\treadonly address: string;\n\treadonly name?: string;\n}\n\nexport interface RegisterDevstackDevWalletConfig {\n\t/** Wallet-app origin (`devWallet.walletUrl`). */\n\treadonly serverOrigin: string;\n\t/** Bearer token (`parseDevstackToken(devWallet.pairUrl)`), or null. */\n\treadonly token?: string | null;\n\t/** Generated name→account map (`accounts` from `generated-extras/accounts.ts`). */\n\treadonly accounts: Readonly<Record<string, DevstackAccountInfo>>;\n\t/** RPC endpoint the wallet uses to execute `signAndExecuteTransaction`\n\t * (and simulate). MUST be the SAME routed RPC the app's dApp Kit client\n\t * uses (`config.networks[config.network].rpc`) — a raw `127.0.0.1:9000`\n\t * is CORS-blocked from the routed page origin. When omitted the wallet\n\t * falls back to localnet defaults (only correct for non-routed setups). */\n\treadonly rpcUrl?: string;\n\t/** Network name the wallet's accounts are scoped to (e.g. `'localnet'`\n\t * from `devWallet.network`). The wallet advertises the wallet-standard\n\t * chain `sui:<network>` derived from it; defaults to `localnet`. */\n\treadonly network?: string;\n\t/** Auto-approve all signing requests (headless e2e). Defaults to false. */\n\treadonly autoApprove?: AutoApprovePolicy;\n\t/** Mount the floating wallet drawer UI. Defaults to true. */\n\treadonly mountUI?: boolean;\n\t/** Wallet display name. Defaults to `'Devstack'`. */\n\treadonly name?: string;\n}\n\nexport interface RegisterDevstackDevWalletResult {\n\treadonly wallet: DevWallet;\n\t/** Unregister the wallet, unmount the UI, and tear down the adapter. */\n\treadonly dispose: () => void;\n}\n\n/** Global marker so tests / the plugin can assert injection happened. */\ndeclare global {\n\t// eslint-disable-next-line no-var\n\tvar __DEV_WALLET_INJECTED__: boolean | undefined;\n\t/** In-flight (or settled) registration promise. Published BEFORE the first\n\t * `await` so concurrent evaluations (HMR / double import) coalesce onto a\n\t * single registration instead of each constructing + registering + mounting\n\t * their own wallet. See `registerDevstackDevWallet`. */\n\t// eslint-disable-next-line no-var\n\tvar __devstackDevWalletPromise__: Promise<RegisterDevstackDevWalletResult> | undefined;\n}\n\n/**\n * Construct + register the devstack dev wallet on the current page and wire\n * the Playwright `connectAs` slot. Idempotent: a second call is a no-op and\n * returns the existing instance.\n *\n * Idempotency is enforced SYNCHRONOUSLY: an in-flight registration promise is\n * published on `globalThis.__devstackDevWalletPromise__` before the first\n * `await`, so two evaluations that race in before the first one finishes both\n * resolve to the SAME wallet instead of double-registering.\n */\nexport function registerDevstackDevWallet(\n\tconfig: RegisterDevstackDevWalletConfig,\n): Promise<RegisterDevstackDevWalletResult> {\n\tconst g = globalThis as {\n\t\t__devstackDevWallet__?: RegisterDevstackDevWalletResult;\n\t\t__devstackDevWalletPromise__?: Promise<RegisterDevstackDevWalletResult>;\n\t};\n\t// Fast path: a prior call already completed.\n\tif (g.__devstackDevWallet__ !== undefined) return Promise.resolve(g.__devstackDevWallet__);\n\t// In-flight path: a prior call is still booting — share its promise. This\n\t// guard runs before any `await`, so it closes the double-init window that a\n\t// post-registration-only marker leaves open under HMR / double import.\n\tif (g.__devstackDevWalletPromise__ !== undefined) return g.__devstackDevWalletPromise__;\n\n\tconst promise = registerDevstackDevWalletImpl(config);\n\tg.__devstackDevWalletPromise__ = promise;\n\t// On failure, clear the in-flight promise so a later call can retry instead\n\t// of being stuck awaiting a rejected registration.\n\tpromise.catch(() => {\n\t\tif (g.__devstackDevWalletPromise__ === promise) {\n\t\t\tg.__devstackDevWalletPromise__ = undefined;\n\t\t}\n\t});\n\treturn promise;\n}\n\nasync function registerDevstackDevWalletImpl(\n\tconfig: RegisterDevstackDevWalletConfig,\n): Promise<RegisterDevstackDevWalletResult> {\n\tconst { mountUI = true, autoApprove = false } = config;\n\tglobalThis.__DEV_WALLET_INJECTED__ = true;\n\n\tconst adapter = new DevstackSignerAdapter({\n\t\tserverOrigin: config.serverOrigin,\n\t\ttoken: config.token ?? null,\n\t\tname: config.name ?? 'Devstack',\n\t});\n\n\t// The wallet EXECUTES (and simulates) `signAndExecuteTransaction` with\n\t// its OWN client — adapter signing is HTTP (server-side keys), but\n\t// execution goes through the wallet's network client. That client MUST\n\t// hit the same routed RPC the app's dApp Kit uses (a raw 127.0.0.1 RPC\n\t// is CORS-blocked from the routed page origin).\n\t//\n\t// Expose a SINGLE network — the active stack's — so the wallet's network\n\t// switcher shows one entry that matches dApp Kit, not a list of unused\n\t// devnet/testnet/mainnet. `mountAndRegisterDevWallet` advertises the\n\t// wallet-standard chain `sui:<network>` derived from this key, matching the\n\t// `sui:<network>` dApp Kit forwards for signing — the `sui:` prefix lives\n\t// only here, at the wallet-standard boundary.\n\tconst rpcUrl = config.rpcUrl ?? 'http://127.0.0.1:9000';\n\tconst activeNetwork = config.network ?? 'localnet';\n\tconst networks: Record<string, string> = { [activeNetwork]: rpcUrl };\n\n\t// Delegate the construct → init-adapter → mount-UI → register → dispose\n\t// sequence to the shared dev-wallet core helper. Two adapters: the\n\t// `DevstackSignerAdapter` brings the stack's server-resolved accounts\n\t// (alice/bob/carol — headless HTTP signing), and a `WebCryptoSignerAdapter`\n\t// lets the user create their OWN accounts in the wallet UI, persisted in\n\t// IndexedDB across reloads (non-extractable WebCrypto keys, NOT in-memory).\n\t// `createInitialAccount` stays off — the devstack adapter already supplies\n\t// accounts, so we never fabricate a throwaway key; the WebCrypto adapter\n\t// starts empty until the user adds one.\n\tconst { wallet, dispose: disposeWallet } = await mountAndRegisterDevWallet({\n\t\tadapters: [adapter, new WebCryptoSignerAdapter()],\n\t\tname: config.name ?? 'Devstack',\n\t\tautoApprove,\n\t\t// Auto-approve `standard:connect` whenever signing is auto-approved — both\n\t\t// are the headless-e2e signal (`DEVSTACK_AUTO_APPROVE`). The test bridge's\n\t\t// explicit `connectWallet(...)` invokes the wallet's connect; without this\n\t\t// it would queue a pending request and block on UI approval that never\n\t\t// comes. In normal dev (no auto-approve) a human approves the connect.\n\t\tautoConnect: Boolean(autoApprove),\n\t\tnetworks,\n\t\tactiveNetwork,\n\t\tmountUI,\n\t});\n\n\tconst result: RegisterDevstackDevWalletResult = {\n\t\twallet,\n\t\tdispose() {\n\t\t\tdisposeWallet();\n\t\t\tglobalThis.__DEV_WALLET_INJECTED__ = false;\n\t\t\tdelete (globalThis as { __devstackDevWallet__?: unknown }).__devstackDevWallet__;\n\t\t\t// Clear the in-flight/settled registration promise too, so a\n\t\t\t// subsequent `registerDevstackDevWallet` re-initializes rather than\n\t\t\t// handing back the disposed instance.\n\t\t\tdelete (globalThis as { __devstackDevWalletPromise__?: unknown })\n\t\t\t\t.__devstackDevWalletPromise__;\n\t\t},\n\t};\n\t(\n\t\tglobalThis as { __devstackDevWallet__?: RegisterDevstackDevWalletResult }\n\t).__devstackDevWallet__ = result;\n\treturn result;\n}\n"],"mappings":";;;;;;;;;;;;;;AAuFA,SAAgB,0BACf,QAC2C;CAC3C,MAAM,IAAI;CAKV,IAAI,EAAE,0BAA0B,QAAW,OAAO,QAAQ,QAAQ,EAAE,qBAAqB;CAIzF,IAAI,EAAE,iCAAiC,QAAW,OAAO,EAAE;CAE3D,MAAM,UAAU,8BAA8B,MAAM;CACpD,EAAE,+BAA+B;CAGjC,QAAQ,YAAY;EACnB,IAAI,EAAE,iCAAiC,SACtC,EAAE,+BAA+B;CAEnC,CAAC;CACD,OAAO;AACR;AAEA,eAAe,8BACd,QAC2C;CAC3C,MAAM,EAAE,UAAU,MAAM,cAAc,UAAU;CAChD,WAAW,0BAA0B;CAErC,MAAM,UAAU,IAAI,sBAAsB;EACzC,cAAc,OAAO;EACrB,OAAO,OAAO,SAAS;EACvB,MAAM,OAAO,QAAQ;CACtB,CAAC;CAcD,MAAM,SAAS,OAAO,UAAU;CAChC,MAAM,gBAAgB,OAAO,WAAW;CACxC,MAAM,WAAmC,GAAG,gBAAgB,OAAO;CAWnE,MAAM,EAAE,QAAQ,SAAS,kBAAkB,MAAM,0BAA0B;EAC1E,UAAU,CAAC,SAAS,IAAI,uBAAuB,CAAC;EAChD,MAAM,OAAO,QAAQ;EACrB;EAMA,aAAa,QAAQ,WAAW;EAChC;EACA;EACA;CACD,CAAC;CAED,MAAM,SAA0C;EAC/C;EACA,UAAU;GACT,cAAc;GACd,WAAW,0BAA0B;GACrC,OAAQ,WAAmD;GAI3D,OAAQ,WACN;EACH;CACD;CACA,WAEE,wBAAwB;CAC1B,OAAO;AACR"}
|
|
@@ -3,27 +3,25 @@ import { DevWalletNewAccount as DevWalletNewAccount$1 } from "../ui/dev-wallet-n
|
|
|
3
3
|
import { DevWalletAccounts as DevWalletAccounts$1 } from "../ui/dev-wallet-accounts.mjs";
|
|
4
4
|
import { DevWalletBalances as DevWalletBalances$1 } from "../ui/dev-wallet-balances.mjs";
|
|
5
5
|
import { DevWalletSigning as DevWalletSigning$1 } from "../ui/dev-wallet-signing.mjs";
|
|
6
|
-
import * as _$_mysten_wallet_standard0 from "@mysten/wallet-standard";
|
|
7
|
-
import * as _$_lit_react0 from "@lit/react";
|
|
8
6
|
import { EventName } from "@lit/react";
|
|
9
7
|
|
|
10
8
|
//#region src/react/components.d.ts
|
|
11
|
-
declare const DevWalletPanel:
|
|
12
|
-
declare const DevWalletAccounts:
|
|
9
|
+
declare const DevWalletPanel: import("@lit/react").ReactWebComponent<DevWalletPanel$1, {}>;
|
|
10
|
+
declare const DevWalletAccounts: import("@lit/react").ReactWebComponent<DevWalletAccounts$1, {
|
|
13
11
|
onAccountSelected: EventName<CustomEvent<{
|
|
14
|
-
account:
|
|
12
|
+
account: import("@mysten/wallet-standard").ReadonlyWalletAccount;
|
|
15
13
|
}>>;
|
|
16
14
|
onAccountRenamed: EventName<CustomEvent<{
|
|
17
15
|
address: string;
|
|
18
16
|
label: string;
|
|
19
17
|
}>>;
|
|
20
18
|
}>;
|
|
21
|
-
declare const DevWalletBalances:
|
|
22
|
-
declare const DevWalletNewAccount:
|
|
19
|
+
declare const DevWalletBalances: import("@lit/react").ReactWebComponent<DevWalletBalances$1, {}>;
|
|
20
|
+
declare const DevWalletNewAccount: import("@lit/react").ReactWebComponent<DevWalletNewAccount$1, {
|
|
23
21
|
onClose: EventName<CustomEvent>;
|
|
24
22
|
onAccountCreated: EventName<CustomEvent>;
|
|
25
23
|
}>;
|
|
26
|
-
declare const DevWalletSigning:
|
|
24
|
+
declare const DevWalletSigning: import("@lit/react").ReactWebComponent<DevWalletSigning$1, {
|
|
27
25
|
onApprove: EventName<CustomEvent>;
|
|
28
26
|
onReject: EventName<CustomEvent>;
|
|
29
27
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.d.mts","names":[],"sources":["../../src/react/components.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components.d.mts","names":[],"sources":["../../src/react/components.ts"],"mappings":";;;;;;;;cAmBa,cAAA,uBAAc,iBAAA,CAAA,gBAAA;AAAA,cAMd,iBAAA,uBAAiB,iBAAA,CAAA,mBAAA;qBAKa,SAAA,CACxC,WAAA;IAAc,OAAA,oCAA2C,qBAAA;EAAA;oBAEnB,SAAA,CACtC,WAAA;IAAc,OAAA;IAAiB,KAAA;EAAA;AAAA;AAAA,cAKrB,iBAAA,uBAAiB,iBAAA,CAAA,mBAAA;AAAA,cAMjB,mBAAA,uBAAmB,iBAAA,CAAA,qBAAA;WAKV,SAAA,CAAU,WAAA;oBACS,SAAA,CAAU,WAAA;AAAA;AAAA,cAItC,gBAAA,uBAAgB,iBAAA,CAAA,kBAAA;aAKH,SAAA,CAAU,WAAA;YACZ,SAAA,CAAU,WAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.mjs","names":["DevWalletPanelElement","DevWalletAccountsElement","DevWalletBalancesElement","DevWalletNewAccountElement","DevWalletSigningElement"],"sources":["../../src/react/components.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nif (typeof customElements === 'undefined') {\n\tthrow new Error(\n\t\t'@mysten-incubation/dev-wallet/react components require a browser environment. ' +\n\t\t\t'Use dynamic imports with ssr:false in Next.js.',\n\t);\n}\n\nimport { createComponent, type EventName } from '@lit/react';\nimport * as React from 'react';\n\nimport { DevWalletAccounts as DevWalletAccountsElement } from '../ui/dev-wallet-accounts.js';\nimport { DevWalletBalances as DevWalletBalancesElement } from '../ui/dev-wallet-balances.js';\nimport { DevWalletNewAccount as DevWalletNewAccountElement } from '../ui/dev-wallet-new-account.js';\nimport { DevWalletPanel as DevWalletPanelElement } from '../ui/dev-wallet-panel.js';\nimport { DevWalletSigning as DevWalletSigningElement } from '../ui/dev-wallet-signing.js';\n\nexport const DevWalletPanel = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-panel',\n\telementClass: DevWalletPanelElement,\n});\n\nexport const DevWalletAccounts = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-accounts',\n\telementClass: DevWalletAccountsElement,\n\tevents: {\n\t\tonAccountSelected: 'account-selected' as EventName<\n\t\t\tCustomEvent<{ account: import('@mysten/wallet-standard').ReadonlyWalletAccount }>\n\t\t>,\n\t\tonAccountRenamed: 'account-renamed' as EventName<\n\t\t\tCustomEvent<{ address: string; label: string }>\n\t\t>,\n\t},\n});\n\nexport const DevWalletBalances = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-balances',\n\telementClass: DevWalletBalancesElement,\n});\n\nexport const DevWalletNewAccount = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-new-account',\n\telementClass: DevWalletNewAccountElement,\n\tevents: {\n\t\tonClose: 'close' as EventName<CustomEvent>,\n\t\tonAccountCreated: 'account-created' as EventName<CustomEvent>,\n\t},\n});\n\nexport const DevWalletSigning = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-signing',\n\telementClass: DevWalletSigningElement,\n\tevents: {\n\t\tonApprove: 'approve' as EventName<CustomEvent>,\n\t\tonReject: 'reject' as EventName<CustomEvent>,\n\t},\n});\n"],"mappings":";;;;;;;;AAGA,IAAI,OAAO,mBAAmB,
|
|
1
|
+
{"version":3,"file":"components.mjs","names":["DevWalletPanelElement","DevWalletAccountsElement","DevWalletBalancesElement","DevWalletNewAccountElement","DevWalletSigningElement"],"sources":["../../src/react/components.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nif (typeof customElements === 'undefined') {\n\tthrow new Error(\n\t\t'@mysten-incubation/dev-wallet/react components require a browser environment. ' +\n\t\t\t'Use dynamic imports with ssr:false in Next.js.',\n\t);\n}\n\nimport { createComponent, type EventName } from '@lit/react';\nimport * as React from 'react';\n\nimport { DevWalletAccounts as DevWalletAccountsElement } from '../ui/dev-wallet-accounts.js';\nimport { DevWalletBalances as DevWalletBalancesElement } from '../ui/dev-wallet-balances.js';\nimport { DevWalletNewAccount as DevWalletNewAccountElement } from '../ui/dev-wallet-new-account.js';\nimport { DevWalletPanel as DevWalletPanelElement } from '../ui/dev-wallet-panel.js';\nimport { DevWalletSigning as DevWalletSigningElement } from '../ui/dev-wallet-signing.js';\n\nexport const DevWalletPanel = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-panel',\n\telementClass: DevWalletPanelElement,\n});\n\nexport const DevWalletAccounts = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-accounts',\n\telementClass: DevWalletAccountsElement,\n\tevents: {\n\t\tonAccountSelected: 'account-selected' as EventName<\n\t\t\tCustomEvent<{ account: import('@mysten/wallet-standard').ReadonlyWalletAccount }>\n\t\t>,\n\t\tonAccountRenamed: 'account-renamed' as EventName<\n\t\t\tCustomEvent<{ address: string; label: string }>\n\t\t>,\n\t},\n});\n\nexport const DevWalletBalances = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-balances',\n\telementClass: DevWalletBalancesElement,\n});\n\nexport const DevWalletNewAccount = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-new-account',\n\telementClass: DevWalletNewAccountElement,\n\tevents: {\n\t\tonClose: 'close' as EventName<CustomEvent>,\n\t\tonAccountCreated: 'account-created' as EventName<CustomEvent>,\n\t},\n});\n\nexport const DevWalletSigning = createComponent({\n\treact: React,\n\ttagName: 'dev-wallet-signing',\n\telementClass: DevWalletSigningElement,\n\tevents: {\n\t\tonApprove: 'approve' as EventName<CustomEvent>,\n\t\tonReject: 'reject' as EventName<CustomEvent>,\n\t},\n});\n"],"mappings":";;;;;;;;AAGA,IAAI,OAAO,mBAAmB,aAC7B,MAAM,IAAI,MACT,8HAED;AAYD,MAAa,iBAAiB,gBAAgB;CAC7C,OAAO;CACP,SAAS;CACT,cAAcA;AACf,CAAC;AAED,MAAa,oBAAoB,gBAAgB;CAChD,OAAO;CACP,SAAS;CACT,cAAcC;CACd,QAAQ;EACP,mBAAmB;EAGnB,kBAAkB;CAGnB;AACD,CAAC;AAED,MAAa,oBAAoB,gBAAgB;CAChD,OAAO;CACP,SAAS;CACT,cAAcC;AACf,CAAC;AAED,MAAa,sBAAsB,gBAAgB;CAClD,OAAO;CACP,SAAS;CACT,cAAcC;CACd,QAAQ;EACP,SAAS;EACT,kBAAkB;CACnB;AACD,CAAC;AAED,MAAa,mBAAmB,gBAAgB;CAC/C,OAAO;CACP,SAAS;CACT,cAAcC;CACd,QAAQ;EACP,WAAW;EACX,UAAU;CACX;AACD,CAAC"}
|
package/dist/react/context.d.mts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { DevWallet } from "../wallet/dev-wallet.mjs";
|
|
2
|
-
import * as _$react from "react";
|
|
3
2
|
import { ReactNode } from "react";
|
|
4
3
|
|
|
5
4
|
//#region src/react/context.d.ts
|
|
6
|
-
declare const DevWalletContext:
|
|
5
|
+
declare const DevWalletContext: import("react").Context<DevWallet | null>;
|
|
7
6
|
interface DevWalletProviderProps {
|
|
8
7
|
wallet: DevWallet;
|
|
9
8
|
children?: ReactNode;
|
|
@@ -11,7 +10,7 @@ interface DevWalletProviderProps {
|
|
|
11
10
|
declare function DevWalletProvider({
|
|
12
11
|
wallet,
|
|
13
12
|
children
|
|
14
|
-
}: DevWalletProviderProps):
|
|
13
|
+
}: DevWalletProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<DevWallet | null>>;
|
|
15
14
|
/**
|
|
16
15
|
* @param wallet - If provided, context is bypassed.
|
|
17
16
|
* @throws If no wallet is provided and no DevWalletProvider is in the tree.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.mts","names":[],"sources":["../../src/react/context.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"context.d.mts","names":[],"sources":["../../src/react/context.ts"],"mappings":";;;;cAQa,gBAAA,kBAAgB,OAAA,CAAA,SAAA;AAAA,UAEZ,sBAAA;EAChB,MAAA,EAAQ,SAAA;EACR,QAAA,GAAW,SAAS;AAAA;AAAA,iBAGL,iBAAA;EAAoB,MAAA;EAAQ;AAAA,GAAY,sBAAA,mBAAsB,wBAAA,iBAAA,aAAA,CAAA,SAAA;AAPjD;AAE7B;;;AAF6B,iBAeb,oBAAA,CAAqB,MAAA,GAAS,SAAA,GAAY,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.mjs","names":[],"sources":["../../src/react/context.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { createContext, createElement, useContext } from 'react';\nimport type { ReactNode } from 'react';\n\nimport type { DevWallet } from '../wallet/dev-wallet.js';\n\nexport const DevWalletContext = createContext<DevWallet | null>(null);\n\nexport interface DevWalletProviderProps {\n\twallet: DevWallet;\n\tchildren?: ReactNode;\n}\n\nexport function DevWalletProvider({ wallet, children }: DevWalletProviderProps) {\n\treturn createElement(DevWalletContext.Provider, { value: wallet }, children);\n}\n\n/**\n * @param wallet - If provided, context is bypassed.\n * @throws If no wallet is provided and no DevWalletProvider is in the tree.\n */\nexport function useDevWalletInstance(wallet?: DevWallet): DevWallet {\n\tconst contextValue = useContext(DevWalletContext);\n\n\tif (wallet) {\n\t\treturn wallet;\n\t}\n\n\tif (!contextValue) {\n\t\tthrow new Error(\n\t\t\t'Could not find DevWalletContext. Ensure that you have set up the DevWalletProvider.',\n\t\t);\n\t}\n\n\treturn contextValue;\n}\n"],"mappings":";;AAQA,MAAa,mBAAmB,cAAgC,
|
|
1
|
+
{"version":3,"file":"context.mjs","names":[],"sources":["../../src/react/context.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { createContext, createElement, useContext } from 'react';\nimport type { ReactNode } from 'react';\n\nimport type { DevWallet } from '../wallet/dev-wallet.js';\n\nexport const DevWalletContext = createContext<DevWallet | null>(null);\n\nexport interface DevWalletProviderProps {\n\twallet: DevWallet;\n\tchildren?: ReactNode;\n}\n\nexport function DevWalletProvider({ wallet, children }: DevWalletProviderProps) {\n\treturn createElement(DevWalletContext.Provider, { value: wallet }, children);\n}\n\n/**\n * @param wallet - If provided, context is bypassed.\n * @throws If no wallet is provided and no DevWalletProvider is in the tree.\n */\nexport function useDevWalletInstance(wallet?: DevWallet): DevWallet {\n\tconst contextValue = useContext(DevWalletContext);\n\n\tif (wallet) {\n\t\treturn wallet;\n\t}\n\n\tif (!contextValue) {\n\t\tthrow new Error(\n\t\t\t'Could not find DevWalletContext. Ensure that you have set up the DevWalletProvider.',\n\t\t);\n\t}\n\n\treturn contextValue;\n}\n"],"mappings":";;AAQA,MAAa,mBAAmB,cAAgC,IAAI;AAOpE,SAAgB,kBAAkB,EAAE,QAAQ,YAAoC;CAC/E,OAAO,cAAc,iBAAiB,UAAU,EAAE,OAAO,OAAO,GAAG,QAAQ;AAC5E;;;;;AAMA,SAAgB,qBAAqB,QAA+B;CACnE,MAAM,eAAe,WAAW,gBAAgB;CAEhD,IAAI,QACH,OAAO;CAGR,IAAI,CAAC,cACJ,MAAM,IAAI,MACT,qFACD;CAGD,OAAO;AACR"}
|