@mysten-incubation/dev-wallet 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @mysten-incubation/dev-wallet
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - d3d3805: Fix scaffolded-app build/dev breakages and dashboard reporting; reshape codegen + tests.
8
+
9
+ - **create-devstack-app**: declare `lit` + `@mysten/signers` (fix `vite build` "failed to resolve
10
+ lit" and the dev-wallet injection crash); run `pnpm codegen` after install when `sui` is on PATH
11
+ (`--no-codegen` to skip); move tests to `tests/unit` · `tests/e2e` · `tests/browser` with a
12
+ standalone `tsconfig.test.json`.
13
+ - **devstack**: the Vite plugin now dedupes only Lit packages hoisted at the app root (phantom
14
+ packages no longer break the production build); `devstack codegen` requires a host `sui` CLI
15
+ (the Docker fallback is removed) and fails fast when it's missing; the vitest/Playwright presets
16
+ adopt the `tests/unit`/`tests/e2e`/`tests/browser` layout; the dashboard surfaces Pyth price
17
+ feeds (`DeepbookInfo.pythFeeds`) and renames `marketMakerRunning` → `hasSeedLiquidity`; fix a
18
+ bug where `devstack up`'s extras emit clobbered the committed `src/generated/.gitignore` with an
19
+ ignore-all policy.
20
+ - **dev-wallet**: the WebCrypto adapter is loaded lazily and gated on the optional
21
+ `@mysten/signers` peer, so an app without it still gets a working dev wallet instead of a hard
22
+ inject crash.
23
+
3
24
  ## 0.4.0
4
25
 
5
26
  ### Minor Changes
@@ -1,6 +1,5 @@
1
1
  import { mountAndRegisterDevWallet } from "../wallet/mount-and-register.mjs";
2
2
  import { DevstackSignerAdapter } from "../adapters/devstack-adapter.mjs";
3
- import { WebCryptoSignerAdapter } from "../adapters/webcrypto-adapter.mjs";
4
3
  //#region src/inject/index.ts
5
4
  /**
6
5
  * Construct + register the devstack dev wallet on the current page and wire
@@ -34,8 +33,15 @@ async function registerDevstackDevWalletImpl(config) {
34
33
  const rpcUrl = config.rpcUrl ?? "http://127.0.0.1:9000";
35
34
  const activeNetwork = config.network ?? "localnet";
36
35
  const networks = { [activeNetwork]: rpcUrl };
36
+ const adapters = [adapter];
37
+ try {
38
+ const { WebCryptoSignerAdapter } = await import("../adapters/webcrypto-adapter.mjs");
39
+ adapters.push(new WebCryptoSignerAdapter());
40
+ } catch (error) {
41
+ console.info("[dev-wallet] @mysten/signers is not installed — WebCrypto account creation is disabled. Install @mysten/signers to enable creating your own accounts in the dev wallet.", error);
42
+ }
37
43
  const { wallet, dispose: disposeWallet } = await mountAndRegisterDevWallet({
38
- adapters: [adapter, new WebCryptoSignerAdapter()],
44
+ adapters,
39
45
  name: config.name ?? "Devstack",
40
46
  autoApprove,
41
47
  autoConnect: Boolean(autoApprove),
@@ -1 +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"}
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 { SignerAdapter } from '../types.js';\nimport type { AutoApprovePolicy, DevWallet } from '../wallet/dev-wallet.js';\nimport { mountAndRegisterDevWallet } from '../wallet/mount-and-register.js';\nimport { DevstackSignerAdapter } from '../adapters/devstack-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. The `DevstackSignerAdapter`\n\t// brings the stack's server-resolved accounts (alice/bob/carol — headless\n\t// HTTP signing) and is always present. The optional `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// but it depends on the OPTIONAL `@mysten/signers` peer. Load it dynamically\n\t// and gate on its presence: an app that doesn't install `@mysten/signers`\n\t// still gets a working dev wallet (just without create-your-own-account)\n\t// instead of a hard inject crash on the unresolved peer. `createInitialAccount`\n\t// stays off — the devstack adapter already supplies accounts, so we never\n\t// fabricate a throwaway key; the WebCrypto adapter starts empty until the\n\t// user adds one.\n\tconst adapters: SignerAdapter[] = [adapter];\n\ttry {\n\t\tconst { WebCryptoSignerAdapter } = await import('../adapters/webcrypto-adapter.js');\n\t\tadapters.push(new WebCryptoSignerAdapter());\n\t} catch (error) {\n\t\tconsole.info(\n\t\t\t'[dev-wallet] @mysten/signers is not installed — WebCrypto account creation is ' +\n\t\t\t\t'disabled. Install @mysten/signers to enable creating your own accounts in the ' +\n\t\t\t\t'dev wallet.',\n\t\t\terror,\n\t\t);\n\t}\n\n\tconst { wallet, dispose: disposeWallet } = await mountAndRegisterDevWallet({\n\t\tadapters,\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;CAenE,MAAM,WAA4B,CAAC,OAAO;CAC1C,IAAI;EACH,MAAM,EAAE,2BAA2B,MAAM,OAAO;EAChD,SAAS,KAAK,IAAI,uBAAuB,CAAC;CAC3C,SAAS,OAAO;EACf,QAAQ,KACP,2KAGA,KACD;CACD;CAEA,MAAM,EAAE,QAAQ,SAAS,kBAAkB,MAAM,0BAA0B;EAC1E;EACA,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mysten-incubation/dev-wallet",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "A modular dev wallet for Sui",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Mysten Labs <build@mystenlabs.com>",
@@ -20,10 +20,10 @@
20
20
  // `registerDAppKitForTesting(dAppKit)` (DEV-only) — it needs the app's dApp
21
21
  // Kit instance, which the wallet has no reference to.
22
22
 
23
+ import type { SignerAdapter } from '../types.js';
23
24
  import type { AutoApprovePolicy, DevWallet } from '../wallet/dev-wallet.js';
24
25
  import { mountAndRegisterDevWallet } from '../wallet/mount-and-register.js';
25
26
  import { DevstackSignerAdapter } from '../adapters/devstack-adapter.js';
26
- import { WebCryptoSignerAdapter } from '../adapters/webcrypto-adapter.js';
27
27
 
28
28
  /** Shape of a single entry in the generated `accounts` map
29
29
  * (`generated-extras/accounts.ts`). Only `address` is consumed here. */
@@ -140,16 +140,33 @@ async function registerDevstackDevWalletImpl(
140
140
  const networks: Record<string, string> = { [activeNetwork]: rpcUrl };
141
141
 
142
142
  // Delegate the construct → init-adapter → mount-UI → register → dispose
143
- // sequence to the shared dev-wallet core helper. Two adapters: the
144
- // `DevstackSignerAdapter` brings the stack's server-resolved accounts
145
- // (alice/bob/carol — headless HTTP signing), and a `WebCryptoSignerAdapter`
143
+ // sequence to the shared dev-wallet core helper. The `DevstackSignerAdapter`
144
+ // brings the stack's server-resolved accounts (alice/bob/carol — headless
145
+ // HTTP signing) and is always present. The optional `WebCryptoSignerAdapter`
146
146
  // lets the user create their OWN accounts in the wallet UI, persisted in
147
- // IndexedDB across reloads (non-extractable WebCrypto keys, NOT in-memory).
148
- // `createInitialAccount` stays off — the devstack adapter already supplies
149
- // accounts, so we never fabricate a throwaway key; the WebCrypto adapter
150
- // starts empty until the user adds one.
147
+ // IndexedDB across reloads (non-extractable WebCrypto keys, NOT in-memory) —
148
+ // but it depends on the OPTIONAL `@mysten/signers` peer. Load it dynamically
149
+ // and gate on its presence: an app that doesn't install `@mysten/signers`
150
+ // still gets a working dev wallet (just without create-your-own-account)
151
+ // instead of a hard inject crash on the unresolved peer. `createInitialAccount`
152
+ // stays off — the devstack adapter already supplies accounts, so we never
153
+ // fabricate a throwaway key; the WebCrypto adapter starts empty until the
154
+ // user adds one.
155
+ const adapters: SignerAdapter[] = [adapter];
156
+ try {
157
+ const { WebCryptoSignerAdapter } = await import('../adapters/webcrypto-adapter.js');
158
+ adapters.push(new WebCryptoSignerAdapter());
159
+ } catch (error) {
160
+ console.info(
161
+ '[dev-wallet] @mysten/signers is not installed — WebCrypto account creation is ' +
162
+ 'disabled. Install @mysten/signers to enable creating your own accounts in the ' +
163
+ 'dev wallet.',
164
+ error,
165
+ );
166
+ }
167
+
151
168
  const { wallet, dispose: disposeWallet } = await mountAndRegisterDevWallet({
152
- adapters: [adapter, new WebCryptoSignerAdapter()],
169
+ adapters,
153
170
  name: config.name ?? 'Devstack',
154
171
  autoApprove,
155
172
  // Auto-approve `standard:connect` whenever signing is auto-approved — both