@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,172 @@
|
|
|
1
1
|
# @mysten-incubation/dev-wallet
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9e1e1be: Dev wallet: explicit test-only connect, no pre-connect or storage seeding.
|
|
8
|
+
|
|
9
|
+
The injected dev wallet no longer seeds dApp Kit's localStorage to fake an auto-connect to a
|
|
10
|
+
specific account on page load. A fresh page now loads disconnected, and dApp Kit's own
|
|
11
|
+
`autoConnect` does only what it's meant to — re-connect a genuine prior session.
|
|
12
|
+
|
|
13
|
+
A new devstack `/dapp-kit` entrypoint exports `registerDAppKitForTesting(dAppKit)`, which the app
|
|
14
|
+
wires DEV-only after `createDAppKit(...)`. It publishes the `connectAs` slot that drives a REAL
|
|
15
|
+
connection through dApp Kit's public API (`connectWallet` / `switchAccount`, resolving accounts by
|
|
16
|
+
label) instead of narrowing/widening the wallet's exposed accounts to exploit reconciliation. The
|
|
17
|
+
dev wallet auto-approves `standard:connect` only when signing is auto-approved (the headless-e2e
|
|
18
|
+
`DEVSTACK_AUTO_APPROVE` signal); in normal dev a human approves the connect. This fixes wallet
|
|
19
|
+
connection under `@mysten/dapp-kit-core` ≥1.6, whose rewritten auto-connect state machine broke
|
|
20
|
+
the old storage-seeding approach.
|
|
21
|
+
|
|
22
|
+
- 11c258a: Auto-inject the devstack dev wallet via the Vite plugin.
|
|
23
|
+
|
|
24
|
+
`@mysten-incubation/dev-wallet` adds a `/inject` entry (`registerDevstackDevWallet`) that
|
|
25
|
+
constructs the dev wallet from a devstack stack's config and registers it on the page via the
|
|
26
|
+
wallet-standard window protocol (plus the Playwright `connectAs` slot). The devstack Vite plugin
|
|
27
|
+
uses it to inject + register the dev wallet in DEV only, so dapp-kit apps discover it through
|
|
28
|
+
wallet-standard with no app-side wiring — apps no longer need a `dapp-kit.dev.ts` or any
|
|
29
|
+
`@devstack-dev` import, and production builds carry no dev-wallet code. The dev wallet exposes all
|
|
30
|
+
of its accounts to the dApp while `connectAs` still drives the active account.
|
|
31
|
+
|
|
32
|
+
- 9e1e1be: The injected devstack dev wallet now bundles a `WebCryptoSignerAdapter` alongside the
|
|
33
|
+
stack's server-resolved accounts, so users can create their own accounts from the wallet UI.
|
|
34
|
+
Created accounts persist across reloads in IndexedDB via non-extractable WebCrypto keys (not
|
|
35
|
+
in-memory), and the stack's `alice`/`bob`/`carol` accounts remain available.
|
|
36
|
+
- 9e1e1be: Disambiguate the conflated `chain` concept into three precise ones: `network` (the
|
|
37
|
+
network name — `localnet`/`testnet`/…), `chainId` (the genesis-digest chain identifier, unique per
|
|
38
|
+
spun-up network), and the wallet-standard `sui:<network>` chain name (derived only at the
|
|
39
|
+
dev-wallet wallet-standard boundary — `sui:` never appears in devstack internals).
|
|
40
|
+
|
|
41
|
+
**Breaking.** The substrate `Identity`/manifest field `chain` is now `network` and holds the bare
|
|
42
|
+
network name (previously a `sui:`-prefixed string). The network parser accepts only canonical
|
|
43
|
+
names — the `local` shorthand and the `sui:`-prefixed alias table are removed (use `localnet`);
|
|
44
|
+
`network ⇄ chain id` is now just a `sui:` prefix, not a lookup table. The sui plugin's resolved
|
|
45
|
+
value, on-disk cache-dir keys, and `chain-probe:`/`faucet:request:` capability keys now key on the
|
|
46
|
+
genesis-digest `chainId`. The generated `config.ts` active-network key is `localnet` (was
|
|
47
|
+
`local`), and `config.networks.<net>` / `byNetwork.<net>` are keyed by network name. The
|
|
48
|
+
dev-wallet `registerDevstackDevWallet` config and `DevWalletConfig` take `network` instead of
|
|
49
|
+
`chain`. The dashboard GraphQL surfaces `chainId` (sui) and `network` (deepbook) instead of
|
|
50
|
+
`chain`. Known walrus/deepbook deployments and the deepbook DEEP-funding gate now key on the
|
|
51
|
+
network name — fixing a latent bug where the gate compared a genesis digest against the
|
|
52
|
+
`'sui:testnet'` literal and was dead for every non-literal value.
|
|
53
|
+
|
|
54
|
+
On-disk state keyed by the old `sui:local` chain brand is invalidated; run `devstack wipe` on
|
|
55
|
+
existing local stacks after upgrading.
|
|
56
|
+
|
|
57
|
+
## 0.3.0
|
|
58
|
+
|
|
59
|
+
### Minor Changes
|
|
60
|
+
|
|
61
|
+
- b6af6d2: Devstack: thorough-review remediation pass plus follow-up cleanup round.
|
|
62
|
+
|
|
63
|
+
Highlights:
|
|
64
|
+
- `runStack({ layers })` replaced by `runStack({ extendContext })`. Custom context extension now
|
|
65
|
+
goes through a typed seam.
|
|
66
|
+
- `executeSuiTx` returns a discriminated union (`$kind: 'ExecutedSuccess' | 'ExecutedFailure'`).
|
|
67
|
+
On-chain failure is a value, not an error. Plugins that previously caught the failure-tag in the
|
|
68
|
+
error channel must dispatch on `$kind` instead.
|
|
69
|
+
- New substrate helper `signAndDispatch` compacts the
|
|
70
|
+
`withTransactionSigner → build → sign → execute → $kind dispatch` pattern across five publisher
|
|
71
|
+
plugins.
|
|
72
|
+
- Supervisor module (1.8k LOC) split into 11 per-concern modules under
|
|
73
|
+
`substrate/runtime/supervisor/`. No behavior change.
|
|
74
|
+
- New `built-in-plugin-layers.ts` lives in `orchestrators/`, not `runtime/` — `run.ts` lifted into
|
|
75
|
+
`orchestrators/` similarly. Layer composition now lives at L3 only.
|
|
76
|
+
- New L0 helper `routed-url.ts` for `renderUrl`/`routedHostname`; L3 router/hostname.ts retained
|
|
77
|
+
as an intra-L3 adapter.
|
|
78
|
+
- Docker image builds now stamp ownership labels (`expectedImageOwnershipLabels`); prune can reach
|
|
79
|
+
previously-unlabelled images. New `BuildOptions.labels` on the container-runtime contract.
|
|
80
|
+
- Sweep evicts own endpoints and surfaces remaining `ForeignNetworkHolder` rather than failing
|
|
81
|
+
silently.
|
|
82
|
+
- Per-app shared-stack pinning: `_per-app_` stacks (e.g. shared chain-build cache) are pinned
|
|
83
|
+
while any app sibling is live.
|
|
84
|
+
- `atomicWriteFile` cleanup is now whole-pipeline (open/write/fsync/rename) via `Effect.onError`,
|
|
85
|
+
not rename-only.
|
|
86
|
+
- `cross-process-lock` typed errors: `StackLockTimeoutError | StackLockIoError` in the E channel;
|
|
87
|
+
no more `Effect.orDie`.
|
|
88
|
+
- Plugin-domain span/log keys namespaced via per-plugin `spans.ts` files.
|
|
89
|
+
- `ChainOperation` typed seam removed (zero plugin adoption signal); `ClientWithCoreApi` is the
|
|
90
|
+
sanctioned SDK cast at plugin boundaries.
|
|
91
|
+
- ARCHITECTURE.md / STYLE_GUIDE.md rewritten to describe current state (537→308, 894→477 lines).
|
|
92
|
+
- New style-enforcement tests: `l4-boundary`, `no-unknown-as` (globs every plugin barrel),
|
|
93
|
+
`plugin-boundary`, `span-attr-namespace`, `substrate/name-blindness`.
|
|
94
|
+
|
|
95
|
+
Dead-code purge and substrate race fixes:
|
|
96
|
+
- Orphan modules removed (no consumers): `orchestrators/codegen/extras.ts` (inlined into
|
|
97
|
+
`runtime-composition.ts`); `plugins/deepbook/routable.ts` + the `DEEPBOOK_ENTRYPOINTS`
|
|
98
|
+
aggregation; `plugins/sui/live-faucet-strategy.ts` (`suiLiveStrategy`, `LIVE_FAUCET_URLS`,
|
|
99
|
+
`SuiLiveNetwork`, `SuiLiveStrategyOptions`); `plugins/sui/seed-objects.ts`
|
|
100
|
+
(`SeedObjectsAccumulator`, `makeSeedObjectsAccumulator`, `SEED_OBJECTS_CAPABILITY_KEY`). The sui
|
|
101
|
+
plugin's emitted-capability count drops from 5 to 4.
|
|
102
|
+
- `plugins/walrus/faucet-strategy.ts`: `makeWalFaucetContribution` removed;
|
|
103
|
+
`makeWalFaucetStrategy` unaffected.
|
|
104
|
+
- `orchestrators/router/index.ts`: unused `STATIC_PROVIDER_FILENAME` export removed.
|
|
105
|
+
- `plugins/sui/fork-orchestration.ts`: `ForkGuardedSdk<Sdk>` derived type alias removed;
|
|
106
|
+
`wrapWithForkGuard` now returns `Sdk` directly (behavior identical).
|
|
107
|
+
- Capability-sink registration race fixed: install + finalizer wrapped in `Effect.uninterruptible`
|
|
108
|
+
so an interrupt between `Ref.modify` and `addFinalizer` cannot leak the sink past scope close.
|
|
109
|
+
- Cross-process command channel short-read fix: `readSync` may short-return on NFS / cross-FS;
|
|
110
|
+
offset advances by `bytesRead` rather than the requested length, with a clean bail on
|
|
111
|
+
`bytesRead <= 0`.
|
|
112
|
+
- Cross-process roster PID-recycle hazard fixed: `heartbeat` / `release` / `setIntent` now match
|
|
113
|
+
holders via `(pid, hostname, startTime)` triple via a new `isOwnEntry` helper (was matching
|
|
114
|
+
`(pid, hostname)` only).
|
|
115
|
+
- Background snapshot interrupt now awaits via `Fiber.interrupt(fiber)` (was fire-and-forget
|
|
116
|
+
`fiber.interruptUnsafe()`) so a follow-up capture can't start while the previous fiber is still
|
|
117
|
+
inside `pauseAndCommit` / `saveImages`.
|
|
118
|
+
- CLI restructure: `cli/main.ts` (1338 LOC) split into per-verb wirings under
|
|
119
|
+
`cli/wirings/{up,apply,snapshot,wipe,prune}.ts` plus shared `build-verb-layers.ts` /
|
|
120
|
+
`identity.ts` / `config-loader.ts` helpers. `main.ts` is now argv → identity → deps → dispatch
|
|
121
|
+
only (~290 LOC).
|
|
122
|
+
- Cross-process command-channel `ack` / `error` records gain an optional `payload: unknown` field
|
|
123
|
+
plumbed through `awaitCompletion`. `snapshot.capture` now carries the captured metadata (or
|
|
124
|
+
failure summary / skipped reason) on the reply directly — the CLI no longer tail-fibers
|
|
125
|
+
`events.ndjson` for the completion event.
|
|
126
|
+
- Repo-wide Prettier reformat.
|
|
127
|
+
|
|
128
|
+
User-visible behavior changes (minor-bump rationale):
|
|
129
|
+
- **Pyth types removed from the root barrel.** `PythFeed`, `PythHandle`, `PythOptions`,
|
|
130
|
+
`PythPackageMember`, and `PythPriceFeedId` no longer re-export from
|
|
131
|
+
`@mysten-incubation/devstack`. They remain reachable via the `DeepbookLocalOptions.pyth` field
|
|
132
|
+
chain. The value helpers (`pythPriceFeedId`, `DEEP_PRICE_FEED_ID`, `SUI_PRICE_FEED_ID`,
|
|
133
|
+
`USDC_PRICE_FEED_ID`) are kept because `examples/deepbook-trader/devstack.config.ts` is the
|
|
134
|
+
market-maker case the architecture permits.
|
|
135
|
+
- **Postgres password format changed.** `derivePassword(app, stack, stackRoot)` now incorporates
|
|
136
|
+
the stack's on-disk runtime root and an sha256 short hash. Existing dev databases created
|
|
137
|
+
against the previous `pg-${app+stack}` format will fail to authenticate on first `pg_isready`
|
|
138
|
+
probe. Delete the existing container (`docker rm -f`) and let devstack recreate it.
|
|
139
|
+
Multi-checkout shells of the same `(app, stack)` now derive distinct passwords by design.
|
|
140
|
+
- **CLI argv-parse failures now exit with code 64 (`USAGE`), not 1 (`GENERIC`).** Tests / CI
|
|
141
|
+
scripts that pattern-match exit codes for "user error vs internal error" should treat 64 the
|
|
142
|
+
same way they treat the `--help` exit code. `--json` mode now also emits a structured envelope
|
|
143
|
+
for these failures instead of plain stderr.
|
|
144
|
+
- **`DevstackOptions.stateDir` is now honored.** The field was declared on the type but silently
|
|
145
|
+
ignored by `runStack` (only `runtimeRoot` was read). Programs that set
|
|
146
|
+
`defineDevstack({ stateDir })` previously had no effect; they now do.
|
|
147
|
+
- **CLI now honors `config.options.stateDir` / `defineDevstack({ stateDir })`.** The `devstack`
|
|
148
|
+
CLI loads the config best-effort before resolving identity and feeds its `stateDir` into the
|
|
149
|
+
runtime-root ladder. Precedence: `--state-dir` flag > `config.options.stateDir` >
|
|
150
|
+
`$DEVSTACK_STATE_DIR` > `<cwd>/.devstack`. The `--state-dir` flag still wins, and no-config
|
|
151
|
+
verbs (`prune`, `wipe`) keep resolving without a config.
|
|
152
|
+
- **`setNetworkEnv` now save/restores `process.env.DEVSTACK_NETWORK`.** In-process CLI invocations
|
|
153
|
+
(tests, embedded use) no longer leak `--network` env state into subsequent calls. Single-process
|
|
154
|
+
CLI semantics are unchanged.
|
|
155
|
+
- **`stringifyCause` renamed to `formatUnknownError`.** Plugins importing the substrate helper
|
|
156
|
+
directly need to update their import (canonical path:
|
|
157
|
+
`substrate/runtime/format-unknown-error.ts`). The function's behavior is unchanged.
|
|
158
|
+
- **Wallet endpoint constant unified.** `WALLET_ENDPOINT_ALIAS` removed; `WALLET_ENDPOINT_KEY` is
|
|
159
|
+
the single canonical name. All exports surface through the same module paths.
|
|
160
|
+
- **`EndpointEntry.wireProtocol`, `Endpoint.wireProtocol`, `ResolvedEndpoint.wireProtocol`**
|
|
161
|
+
narrowed from `'http' | 'h2c' | string` to `'http' | 'h2c' | 'tcp'`. Persisted manifests and
|
|
162
|
+
projections now reject other values at decode time. Plugins emitting custom wire protocols (none
|
|
163
|
+
ship today) would need to extend the literal union.
|
|
164
|
+
|
|
165
|
+
dev-wallet:
|
|
166
|
+
- `DEVSTACK_WALLET_HTTP_PATH.EXECUTE` removed (devstack-side `/execute` endpoint deleted; the
|
|
167
|
+
dapp-kit / dev-wallet path bypasses it and the protocol shape didn't match the Sui Wallet
|
|
168
|
+
Standard).
|
|
169
|
+
|
|
3
170
|
## 0.2.0
|
|
4
171
|
|
|
5
172
|
### Minor Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/decorate.js
|
|
2
2
|
function __decorate(decorators, target, key, desc) {
|
|
3
3
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
4
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.d.mts","names":[],"sources":["../../src/adapters/base-adapter.ts"],"mappings":";;;;;AAYA;;;;uBAAsB,iBAAA,YAA6B,aAAA;EAAA;oBAChC,EAAA;EAAA,kBACA,IAAA;EAAA,SACT,aAAA;EAAA,SAKA,UAAA,
|
|
1
|
+
{"version":3,"file":"base-adapter.d.mts","names":[],"sources":["../../src/adapters/base-adapter.ts"],"mappings":";;;;;AAYA;;;;uBAAsB,iBAAA,YAA6B,aAAA;EAAA;oBAChC,EAAA;EAAA,kBACA,IAAA;EAAA,SACT,aAAA;EAAA,SAKA,UAAA,IAAc,OAAA;EAEvB,WAAA,IAAe,cAAA;EAIf,UAAA,CAAW,OAAA,WAAkB,cAAA;EAI7B,iBAAA,CAAkB,QAAA,GAAW,QAAA,EAAU,cAAA;EAOvC,OAAA;EAAA,cAOc,SAAA,aAAsB,cAAA;EAAA,UAI1B,kBAAA,CAAmB,QAAA,EAAU,cAAA;EAAA,UAK7B,UAAA,CAAW,OAAA,EAAS,cAAA;EAAA,UAKpB,sBAAA,CAAuB,OAAA;EA3CxB;EAAA,UAoDC,cAAA,CAAe,OAAA,UAAiB,OAAA,EAAS,cAAA;EA/C5B;EAAA,UAwDb,cAAA,CAAe,OAAA,UAAiB,KAAA;EAAA,UAMhC,eAAA;EAAA,UAIA,eAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.mjs","names":["#accounts","#listeners"],"sources":["../../src/adapters/base-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ManagedAccount, SignerAdapter } from '../types.js';\nimport { buildManagedAccount } from './build-managed-account.js';\n\n/**\n * Abstract base class implementing the shared boilerplate of {@link SignerAdapter}.\n *\n * Subclasses only need to implement `initialize()`, `id`, and `name`.\n * All account list management, listener notification, and cleanup are handled here.\n */\nexport abstract class BaseSignerAdapter implements SignerAdapter {\n\tabstract readonly id: string;\n\tabstract readonly name: string;\n\treadonly allowAutoSign: boolean = true;\n\n\t#accounts: ManagedAccount[] = [];\n\t#listeners = new Set<(accounts: ManagedAccount[]) => void>();\n\n\tabstract initialize(): Promise<void>;\n\n\tgetAccounts(): ManagedAccount[] {\n\t\treturn [...this.#accounts];\n\t}\n\n\tgetAccount(address: string): ManagedAccount | undefined {\n\t\treturn this.#accounts.find((account) => account.address === address);\n\t}\n\n\tonAccountsChanged(callback: (accounts: ManagedAccount[]) => void): () => void {\n\t\tthis.#listeners.add(callback);\n\t\treturn () => {\n\t\t\tthis.#listeners.delete(callback);\n\t\t};\n\t}\n\n\tdestroy(): void {\n\t\tthis.#accounts = [];\n\t\tthis.#listeners.clear();\n\t}\n\n\t// ── Protected helpers for subclasses ─────────────────────────────────────\n\n\tprotected get _accounts(): readonly ManagedAccount[] {\n\t\treturn this.#accounts;\n\t}\n\n\tprotected setInitialAccounts(accounts: ManagedAccount[]): void {\n\t\tthis.#accounts = accounts;\n\t\tthis.notifyListeners();\n\t}\n\n\tprotected addAccount(account: ManagedAccount): void {\n\t\tthis.#accounts.push(account);\n\t\tthis.notifyListeners();\n\t}\n\n\tprotected removeAccountByAddress(address: string): boolean {\n\t\tconst index = this.#accounts.findIndex((a) => a.address === address);\n\t\tif (index === -1) return false;\n\t\tthis.#accounts.splice(index, 1);\n\t\tthis.notifyListeners();\n\t\treturn true;\n\t}\n\n\t/** Replace an account by address (e.g. after rename). */\n\tprotected replaceAccount(address: string, account: ManagedAccount): boolean {\n\t\tconst index = this.#accounts.findIndex((a) => a.address === address);\n\t\tif (index === -1) return false;\n\t\tthis.#accounts[index] = account;\n\t\tthis.notifyListeners();\n\t\treturn true;\n\t}\n\n\t/** Rename an account by rebuilding its ManagedAccount with a new label. */\n\tprotected _performRename(address: string, label: string): boolean {\n\t\tconst account = this.getAccount(address);\n\t\tif (!account) return false;\n\t\treturn this.replaceAccount(address, buildManagedAccount(account.signer, address, label));\n\t}\n\n\tprotected getDefaultLabel(): string {\n\t\treturn `Account ${this.getAccounts().length + 1}`;\n\t}\n\n\tprotected notifyListeners(): void {\n\t\tconst accounts = this.getAccounts();\n\t\tfor (const listener of this.#listeners) {\n\t\t\tlistener(accounts);\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;AAYA,IAAsB,oBAAtB,MAAiE;;uBAG9B;mBAEJ,
|
|
1
|
+
{"version":3,"file":"base-adapter.mjs","names":["#accounts","#listeners"],"sources":["../../src/adapters/base-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ManagedAccount, SignerAdapter } from '../types.js';\nimport { buildManagedAccount } from './build-managed-account.js';\n\n/**\n * Abstract base class implementing the shared boilerplate of {@link SignerAdapter}.\n *\n * Subclasses only need to implement `initialize()`, `id`, and `name`.\n * All account list management, listener notification, and cleanup are handled here.\n */\nexport abstract class BaseSignerAdapter implements SignerAdapter {\n\tabstract readonly id: string;\n\tabstract readonly name: string;\n\treadonly allowAutoSign: boolean = true;\n\n\t#accounts: ManagedAccount[] = [];\n\t#listeners = new Set<(accounts: ManagedAccount[]) => void>();\n\n\tabstract initialize(): Promise<void>;\n\n\tgetAccounts(): ManagedAccount[] {\n\t\treturn [...this.#accounts];\n\t}\n\n\tgetAccount(address: string): ManagedAccount | undefined {\n\t\treturn this.#accounts.find((account) => account.address === address);\n\t}\n\n\tonAccountsChanged(callback: (accounts: ManagedAccount[]) => void): () => void {\n\t\tthis.#listeners.add(callback);\n\t\treturn () => {\n\t\t\tthis.#listeners.delete(callback);\n\t\t};\n\t}\n\n\tdestroy(): void {\n\t\tthis.#accounts = [];\n\t\tthis.#listeners.clear();\n\t}\n\n\t// ── Protected helpers for subclasses ─────────────────────────────────────\n\n\tprotected get _accounts(): readonly ManagedAccount[] {\n\t\treturn this.#accounts;\n\t}\n\n\tprotected setInitialAccounts(accounts: ManagedAccount[]): void {\n\t\tthis.#accounts = accounts;\n\t\tthis.notifyListeners();\n\t}\n\n\tprotected addAccount(account: ManagedAccount): void {\n\t\tthis.#accounts.push(account);\n\t\tthis.notifyListeners();\n\t}\n\n\tprotected removeAccountByAddress(address: string): boolean {\n\t\tconst index = this.#accounts.findIndex((a) => a.address === address);\n\t\tif (index === -1) return false;\n\t\tthis.#accounts.splice(index, 1);\n\t\tthis.notifyListeners();\n\t\treturn true;\n\t}\n\n\t/** Replace an account by address (e.g. after rename). */\n\tprotected replaceAccount(address: string, account: ManagedAccount): boolean {\n\t\tconst index = this.#accounts.findIndex((a) => a.address === address);\n\t\tif (index === -1) return false;\n\t\tthis.#accounts[index] = account;\n\t\tthis.notifyListeners();\n\t\treturn true;\n\t}\n\n\t/** Rename an account by rebuilding its ManagedAccount with a new label. */\n\tprotected _performRename(address: string, label: string): boolean {\n\t\tconst account = this.getAccount(address);\n\t\tif (!account) return false;\n\t\treturn this.replaceAccount(address, buildManagedAccount(account.signer, address, label));\n\t}\n\n\tprotected getDefaultLabel(): string {\n\t\treturn `Account ${this.getAccounts().length + 1}`;\n\t}\n\n\tprotected notifyListeners(): void {\n\t\tconst accounts = this.getAccounts();\n\t\tfor (const listener of this.#listeners) {\n\t\t\tlistener(accounts);\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;AAYA,IAAsB,oBAAtB,MAAiE;;uBAG9B;mBAEJ,CAAC;oCAClB,IAAI,IAA0C;;CAD3D;CACA;CAIA,cAAgC;EAC/B,OAAO,CAAC,GAAG,KAAKA,SAAS;CAC1B;CAEA,WAAW,SAA6C;EACvD,OAAO,KAAKA,UAAU,MAAM,YAAY,QAAQ,YAAY,OAAO;CACpE;CAEA,kBAAkB,UAA4D;EAC7E,KAAKC,WAAW,IAAI,QAAQ;EAC5B,aAAa;GACZ,KAAKA,WAAW,OAAO,QAAQ;EAChC;CACD;CAEA,UAAgB;EACf,KAAKD,YAAY,CAAC;EAClB,KAAKC,WAAW,MAAM;CACvB;CAIA,IAAc,YAAuC;EACpD,OAAO,KAAKD;CACb;CAEA,mBAA6B,UAAkC;EAC9D,KAAKA,YAAY;EACjB,KAAK,gBAAgB;CACtB;CAEA,WAAqB,SAA+B;EACnD,KAAKA,UAAU,KAAK,OAAO;EAC3B,KAAK,gBAAgB;CACtB;CAEA,uBAAiC,SAA0B;EAC1D,MAAM,QAAQ,KAAKA,UAAU,WAAW,MAAM,EAAE,YAAY,OAAO;EACnE,IAAI,UAAU,IAAI,OAAO;EACzB,KAAKA,UAAU,OAAO,OAAO,CAAC;EAC9B,KAAK,gBAAgB;EACrB,OAAO;CACR;;CAGA,eAAyB,SAAiB,SAAkC;EAC3E,MAAM,QAAQ,KAAKA,UAAU,WAAW,MAAM,EAAE,YAAY,OAAO;EACnE,IAAI,UAAU,IAAI,OAAO;EACzB,KAAKA,UAAU,SAAS;EACxB,KAAK,gBAAgB;EACrB,OAAO;CACR;;CAGA,eAAyB,SAAiB,OAAwB;EACjE,MAAM,UAAU,KAAK,WAAW,OAAO;EACvC,IAAI,CAAC,SAAS,OAAO;EACrB,OAAO,KAAK,eAAe,SAAS,oBAAoB,QAAQ,QAAQ,SAAS,KAAK,CAAC;CACxF;CAEA,kBAAoC;EACnC,OAAO,WAAW,KAAK,YAAY,CAAC,CAAC,SAAS;CAC/C;CAEA,kBAAkC;EACjC,MAAM,WAAW,KAAK,YAAY;EAClC,KAAK,MAAM,YAAY,KAAKC,YAC3B,SAAS,QAAQ;CAEnB;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-managed-account.mjs","names":[],"sources":["../../src/adapters/build-managed-account.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Signer } from '@mysten/sui/cryptography';\nimport type { IdentifierString } from '@mysten/wallet-standard';\nimport { ReadonlyWalletAccount, SUI_CHAINS } from '@mysten/wallet-standard';\n\nimport type { ManagedAccount } from '../types.js';\n\nconst DEFAULT_FEATURES: IdentifierString[] = [\n\t'sui:signTransaction',\n\t'sui:signAndExecuteTransaction',\n\t'sui:signPersonalMessage',\n];\n\n/**\n * Build a {@link ManagedAccount} from a signer, address, label, and optional feature list.\n */\nexport function buildManagedAccount(\n\tsigner: Signer,\n\taddress: string,\n\tlabel: string,\n\tfeatures?: readonly IdentifierString[],\n): ManagedAccount {\n\tconst walletAccount = new ReadonlyWalletAccount({\n\t\taddress,\n\t\tlabel,\n\t\tpublicKey: signer.getPublicKey().toSuiBytes(),\n\t\tchains: [...SUI_CHAINS],\n\t\tfeatures: [...(features ?? DEFAULT_FEATURES)],\n\t});\n\treturn { address, label, signer, walletAccount };\n}\n"],"mappings":";;AASA,MAAM,mBAAuC;CAC5C;CACA;CACA;
|
|
1
|
+
{"version":3,"file":"build-managed-account.mjs","names":[],"sources":["../../src/adapters/build-managed-account.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Signer } from '@mysten/sui/cryptography';\nimport type { IdentifierString } from '@mysten/wallet-standard';\nimport { ReadonlyWalletAccount, SUI_CHAINS } from '@mysten/wallet-standard';\n\nimport type { ManagedAccount } from '../types.js';\n\nconst DEFAULT_FEATURES: IdentifierString[] = [\n\t'sui:signTransaction',\n\t'sui:signAndExecuteTransaction',\n\t'sui:signPersonalMessage',\n];\n\n/**\n * Build a {@link ManagedAccount} from a signer, address, label, and optional feature list.\n */\nexport function buildManagedAccount(\n\tsigner: Signer,\n\taddress: string,\n\tlabel: string,\n\tfeatures?: readonly IdentifierString[],\n): ManagedAccount {\n\tconst walletAccount = new ReadonlyWalletAccount({\n\t\taddress,\n\t\tlabel,\n\t\tpublicKey: signer.getPublicKey().toSuiBytes(),\n\t\tchains: [...SUI_CHAINS],\n\t\tfeatures: [...(features ?? DEFAULT_FEATURES)],\n\t});\n\treturn { address, label, signer, walletAccount };\n}\n"],"mappings":";;AASA,MAAM,mBAAuC;CAC5C;CACA;CACA;AACD;;;;AAKA,SAAgB,oBACf,QACA,SACA,OACA,UACiB;CAQjB,OAAO;EAAE;EAAS;EAAO;EAAQ,mBAPP,sBAAsB;GAC/C;GACA;GACA,WAAW,OAAO,aAAa,CAAC,CAAC,WAAW;GAC5C,QAAQ,CAAC,GAAG,UAAU;GACtB,UAAU,CAAC,GAAI,YAAY,gBAAiB;EAC7C,CACiC;CAAc;AAChD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devstack-adapter.d.mts","names":[],"sources":["../../src/adapters/devstack-adapter.ts"],"mappings":";;;;;AAiEA;;;;cAAa,mBAAA,SAA4B,MAAA;EAAA;cAO5B,OAAA;IACX,OAAA;IACA,SAAA,EAAW,SAAA;IACX,MAAA,EAAQ,eAAA;IACR,YAAA;IACA,SAAA;EAAA;EAUK,IAAA,CAAK,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,UAAA,CAAW,WAAA;EAOnD,YAAA,
|
|
1
|
+
{"version":3,"file":"devstack-adapter.d.mts","names":[],"sources":["../../src/adapters/devstack-adapter.ts"],"mappings":";;;;;AAiEA;;;;cAAa,mBAAA,SAA4B,MAAA;EAAA;cAO5B,OAAA;IACX,OAAA;IACA,SAAA,EAAW,SAAA;IACX,MAAA,EAAQ,eAAA;IACR,YAAA;IACA,SAAA;EAAA;EAUK,IAAA,CAAK,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,UAAA,CAAW,WAAA;EAOnD,YAAA,IAAgB,eAAA;EAIhB,YAAA,IAAgB,SAAA;EAIP,YAAA;EAIM,eAAA,CAAgB,KAAA,EAAO,UAAA,GAAU,OAAA;;;;EAqCjC,mBAAA,CAAoB,KAAA,EAAO,UAAA,GAAU,OAAA;;;;;UAyCpC,4BAAA;EA3Gf;;EA8GD,YAAA;EApGmB;;EAuGnB,KAAA;EAvGwC;EAyGxC,IAAA;AAAA;;;;;;;;;;;;;;;;;;;AARD;;cA+Ba,qBAAA,SAA8B,iBAAA;EAAA;WACjC,EAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;cAKG,OAAA,EAAS,4BAAA;EAYf,UAAA,IAAc,OAAA;EAaX,OAAA;AAAA;;;;;;;;;;iBAyCM,kBAAA,CAAmB,SAA6B;;;;;;;;UAsB/C,uBAAA;EAChB,GAAA;IACC,MAAA;MACC,GAAA;MACA,OAAA;IAAA;EAAA;AAAA;;;;;;;;;AAAO;AAiBV;;;iBAAgB,iCAAA,CACf,QAAA,EAAU,uBAAA,GACR,qBAAqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devstack-adapter.mjs","names":["#address","#publicKey","#scheme","#serverOrigin","#authToken","#fetchAccounts"],"sources":["../../src/adapters/devstack-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n//\n// Devstack signer adapter — exposes accounts resolved by `devstack up`'s\n// `wallet()` plugin to dApp Kit, signing transactions over HTTP so\n// private keys never enter the frontend bundle. Mirrors RemoteCliAdapter's\n// out-of-process model; the difference is the source of accounts (devstack\n// resolved signers vs `sui keytool list`) and the endpoint paths.\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';\n\nimport type { ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\nimport { DEVSTACK_WALLET_HTTP_PATH } from './devstack-paths.js';\n\nconst DEVSTACK_WALLET_FEATURES = [\n\t'sui:signTransaction',\n\t'sui:signAndExecuteTransaction',\n\t'sui:signPersonalMessage',\n] as const;\n\ninterface ServerAccountInfo {\n\tname: string;\n\taddress: string;\n\tscheme: SignatureScheme;\n\tpublicKey: string;\n}\n\nclass AuthError extends Error {\n\tconstructor() {\n\t\tsuper('Unauthorized');\n\t\tthis.name = 'AuthError';\n\t}\n}\n\nfunction publicKeyForScheme(base64: string, scheme: SignatureScheme | string): PublicKey {\n\tconst bytes = fromBase64(base64);\n\t// The devstack server's wallet-app endpoint surfaces the scheme in\n\t// the lowercase form it standardised at the Account boundary\n\t// (`'ed25519'`, `'secp256k1'`, `'secp256r1'`). The Sui SDK's\n\t// `SignatureScheme` union is mixed-case (`'ED25519'`, `'Secp256k1'`,\n\t// …). Normalise to lowercase before matching so either casing parses.\n\tswitch (String(scheme).toLowerCase()) {\n\t\tcase 'ed25519':\n\t\t\treturn new Ed25519PublicKey(bytes);\n\t\tcase 'secp256k1':\n\t\t\treturn new Secp256k1PublicKey(bytes);\n\t\tcase 'secp256r1':\n\t\t\treturn new Secp256r1PublicKey(bytes);\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported key scheme: ${scheme}`);\n\t}\n}\n\n/**\n * Signer that delegates transaction signing to the devstack wallet-app\n * over HTTP. Mirrors {@link CliProxySigner} but talks to the\n * `wallet()` plugin's endpoints under `/api/v1/devstack/*`.\n */\nexport class DevstackProxySigner 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'DevstackProxySigner does not support raw digest signing. ' +\n\t\t\t\t'Use signTransaction (the wallet-app signs BCS-serialized TransactionData).',\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 !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst requestBytes = toBase64(bytes);\n\t\tconst res = await fetch(`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.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\tbytes: requestBytes,\n\t\t\t}),\n\t\t});\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.json().catch(() => ({}));\n\t\t\tconst message = (body as { error?: unknown }).error;\n\t\t\tthrow new Error(\n\t\t\t\t`Devstack signing failed: ${typeof message === 'string' ? message : res.statusText}`,\n\t\t\t);\n\t\t}\n\t\tconst { bytes: responseBytes, signature } = (await res.json()) as {\n\t\t\tbytes?: string;\n\t\t\tsignature?: string;\n\t\t};\n\t\tif (typeof responseBytes !== 'string' || responseBytes.length === 0) {\n\t\t\tthrow new Error('Devstack signing failed: server returned invalid signed bytes');\n\t\t}\n\t\tif (typeof signature !== 'string' || signature.length === 0) {\n\t\t\tthrow new Error('Devstack signing failed: server returned invalid signature');\n\t\t}\n\t\treturn {\n\t\t\tbytes: responseBytes,\n\t\t\tsignature,\n\t\t};\n\t}\n\n\toverride async signPersonalMessage(bytes: Uint8Array) {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst res = await fetch(\n\t\t\t`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.SIGN_PERSONAL_MESSAGE}`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\taddress: this.#address,\n\t\t\t\t\tbytes: toBase64(bytes),\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.json().catch(() => ({}));\n\t\t\tconst message = (body as { error?: unknown }).error;\n\t\t\tthrow new Error(\n\t\t\t\t`Devstack personal-message signing failed: ${\n\t\t\t\t\ttypeof message === 'string' ? message : res.statusText\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tconst { bytes: responseBytes, signature } = (await res.json()) as {\n\t\t\tbytes?: string;\n\t\t\tsignature?: string;\n\t\t};\n\t\tif (typeof responseBytes !== 'string' || responseBytes.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Devstack personal-message signing failed: server returned invalid signed bytes',\n\t\t\t);\n\t\t}\n\t\tif (typeof signature !== 'string' || signature.length === 0) {\n\t\t\tthrow new Error('Devstack personal-message signing failed: server returned no signature');\n\t\t}\n\t\treturn { bytes: responseBytes, signature };\n\t}\n}\n\nexport interface DevstackSignerAdapterOptions {\n\t/** Wallet-app origin (e.g. `http://localhost:9420`). Read from the\n\t * matching endpoint entry on the active manifest. */\n\tserverOrigin: string;\n\t/** Bearer token. Parse `?token=<hex>` from the manifest entry's\n\t * `pairUrl`. Omit if the wallet-app runs without auth. */\n\ttoken?: string | null;\n\t/** Override the adapter's display name. Defaults to `'Devstack'`. */\n\tname?: string;\n}\n\n/**\n * {@link SignerAdapter} that surfaces every account resolved by `devstack up`\n * (including `cliSigner`/`envSigner`/`generatedKeypair` slots) without\n * shipping their private keys into the frontend bundle. All signing happens\n * server-side via the `wallet()` plugin.\n *\n * The simplest construction uses devstack's generated `dapp-kit-config.ts`,\n * which bakes the wallet adapter wiring at codegen time — apps spread\n * `devstackDappKitConfig` into `createDAppKit(...)` and never touch the\n * adapter directly.\n *\n * To construct one manually (e.g. from a non-manifest source):\n *\n * ```ts\n * const adapter = new DevstackSignerAdapter({\n * serverOrigin: 'http://localhost:9420',\n * token: '<bearer hex>',\n * });\n * ```\n */\nexport class DevstackSignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'devstack';\n\treadonly name: string;\n\treadonly allowAutoSign = true;\n\n\t#serverOrigin: string;\n\t#authToken: string | null;\n\n\tconstructor(options: DevstackSignerAdapterOptions) {\n\t\tsuper();\n\t\ttry {\n\t\t\tnew URL(options.serverOrigin);\n\t\t} catch {\n\t\t\tthrow new Error(`DevstackSignerAdapter: invalid serverOrigin \"${options.serverOrigin}\"`);\n\t\t}\n\t\tthis.#serverOrigin = options.serverOrigin;\n\t\tthis.#authToken = options.token ?? null;\n\t\tthis.name = options.name ?? 'Devstack';\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\ttry {\n\t\t\tconst accounts = await this.#fetchAccounts();\n\t\t\tthis.setInitialAccounts(accounts);\n\t\t} catch (error) {\n\t\t\tif (error instanceof AuthError) {\n\t\t\t\tconsole.warn('[dev-wallet] devstack adapter: unauthorized — skipping account import');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconsole.warn('[dev-wallet] devstack adapter: initialization failed:', error);\n\t\t}\n\t}\n\n\toverride destroy(): void {\n\t\tthis.#authToken = null;\n\t\tsuper.destroy();\n\t}\n\n\tasync #fetchAccounts(): Promise<ManagedAccount[]> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst res = await fetch(`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.ACCOUNTS}`, {\n\t\t\theaders,\n\t\t});\n\t\tif (res.status === 401 || res.status === 403) throw new AuthError();\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`Failed to fetch devstack accounts: ${res.statusText}`);\n\t\t}\n\t\tconst { accounts } = (await res.json()) as { accounts: ServerAccountInfo[] };\n\t\treturn accounts.map((info) => {\n\t\t\tconst publicKey = publicKeyForScheme(info.publicKey, info.scheme);\n\t\t\tconst signer = new DevstackProxySigner({\n\t\t\t\taddress: info.address,\n\t\t\t\tpublicKey,\n\t\t\t\tscheme: info.scheme,\n\t\t\t\tserverOrigin: this.#serverOrigin,\n\t\t\t\tauthToken: this.#authToken,\n\t\t\t});\n\t\t\treturn buildManagedAccount(signer, info.address, info.name, DEVSTACK_WALLET_FEATURES);\n\t\t});\n\t}\n}\n\n/**\n * Pull the bearer token off a paired URL produced by the `wallet()`\n * plugin. Returns `null` if the input is undefined, malformed, or\n * carries a `<redacted>` placeholder (the manifest's pairUrl carries\n * the redacted form; the real token lives in a sibling 0o600 file the\n * consumer reads separately).\n *\n * The token rides in the URL fragment as `#token=<hex>`.\n */\nexport function parseDevstackToken(pairedUrl: string | undefined): string | null {\n\tif (pairedUrl === undefined) return null;\n\ttry {\n\t\tconst url = new URL(pairedUrl);\n\t\tconst hash = url.hash; // e.g. \"#token=abcd\"\n\t\tif (hash.length <= 1) return null;\n\t\tconst params = new URLSearchParams(hash.slice(1));\n\t\tconst token = params.get('token');\n\t\tif (token === null || token === '<redacted>') return null;\n\t\treturn token;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Narrow input — the only field the adapter consumes is\n * `app.wallet.{url, pairUrl}`. Codegen emits exactly this shape so\n * generated `dapp-kit-config.ts` doesn't have to fabricate placeholder\n * manifest fields (`stack.app`, `coins`, etc.) just to satisfy the\n * full `Manifest` type. Mirrors a slice of `AppManifest` from\n * `@mysten-incubation/devstack` without importing it (dev-wallet\n * doesn't depend on devstack — circular). */\nexport interface DevstackAdapterManifest {\n\tapp?: {\n\t\twallet?: {\n\t\t\turl: string;\n\t\t\tpairUrl?: string;\n\t\t};\n\t};\n}\n\n/**\n * Convenience: read the wallet-app endpoint off a devstack manifest and\n * build a configured adapter, or return `null` when the entry isn't\n * present (no `wallet(...)` in the stack, or it hasn't come up yet).\n *\n * The wallet entry's `pairUrl` carries the `#token=…` fragment used to\n * extract the bearer token. The full `Manifest` shape from\n * `@mysten-incubation/devstack` is structurally compatible with\n * {@link DevstackAdapterManifest}, so\n * `createDevstackAdapterFromManifest(devstackManifest)` typechecks\n * without a cast.\n */\nexport function createDevstackAdapterFromManifest(\n\tmanifest: DevstackAdapterManifest,\n): DevstackSignerAdapter | null {\n\tconst wallet = manifest.app?.wallet;\n\tif (wallet === undefined) return null;\n\treturn new DevstackSignerAdapter({\n\t\tserverOrigin: wallet.url,\n\t\ttoken: parseDevstackToken(wallet.pairUrl),\n\t});\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"devstack-adapter.mjs","names":["#address","#publicKey","#scheme","#serverOrigin","#authToken","#fetchAccounts"],"sources":["../../src/adapters/devstack-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n//\n// Devstack signer adapter — exposes accounts resolved by `devstack up`'s\n// `wallet()` plugin to dApp Kit, signing transactions over HTTP so\n// private keys never enter the frontend bundle. Mirrors RemoteCliAdapter's\n// out-of-process model; the difference is the source of accounts (devstack\n// resolved signers vs `sui keytool list`) and the endpoint paths.\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';\n\nimport type { ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\nimport { DEVSTACK_WALLET_HTTP_PATH } from './devstack-paths.js';\n\nconst DEVSTACK_WALLET_FEATURES = [\n\t'sui:signTransaction',\n\t'sui:signAndExecuteTransaction',\n\t'sui:signPersonalMessage',\n] as const;\n\ninterface ServerAccountInfo {\n\tname: string;\n\taddress: string;\n\tscheme: SignatureScheme;\n\tpublicKey: string;\n}\n\nclass AuthError extends Error {\n\tconstructor() {\n\t\tsuper('Unauthorized');\n\t\tthis.name = 'AuthError';\n\t}\n}\n\nfunction publicKeyForScheme(base64: string, scheme: SignatureScheme | string): PublicKey {\n\tconst bytes = fromBase64(base64);\n\t// The devstack server's wallet-app endpoint surfaces the scheme in\n\t// the lowercase form it standardised at the Account boundary\n\t// (`'ed25519'`, `'secp256k1'`, `'secp256r1'`). The Sui SDK's\n\t// `SignatureScheme` union is mixed-case (`'ED25519'`, `'Secp256k1'`,\n\t// …). Normalise to lowercase before matching so either casing parses.\n\tswitch (String(scheme).toLowerCase()) {\n\t\tcase 'ed25519':\n\t\t\treturn new Ed25519PublicKey(bytes);\n\t\tcase 'secp256k1':\n\t\t\treturn new Secp256k1PublicKey(bytes);\n\t\tcase 'secp256r1':\n\t\t\treturn new Secp256r1PublicKey(bytes);\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported key scheme: ${scheme}`);\n\t}\n}\n\n/**\n * Signer that delegates transaction signing to the devstack wallet-app\n * over HTTP. Mirrors {@link CliProxySigner} but talks to the\n * `wallet()` plugin's endpoints under `/api/v1/devstack/*`.\n */\nexport class DevstackProxySigner 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'DevstackProxySigner does not support raw digest signing. ' +\n\t\t\t\t'Use signTransaction (the wallet-app signs BCS-serialized TransactionData).',\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 !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst requestBytes = toBase64(bytes);\n\t\tconst res = await fetch(`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.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\tbytes: requestBytes,\n\t\t\t}),\n\t\t});\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.json().catch(() => ({}));\n\t\t\tconst message = (body as { error?: unknown }).error;\n\t\t\tthrow new Error(\n\t\t\t\t`Devstack signing failed: ${typeof message === 'string' ? message : res.statusText}`,\n\t\t\t);\n\t\t}\n\t\tconst { bytes: responseBytes, signature } = (await res.json()) as {\n\t\t\tbytes?: string;\n\t\t\tsignature?: string;\n\t\t};\n\t\tif (typeof responseBytes !== 'string' || responseBytes.length === 0) {\n\t\t\tthrow new Error('Devstack signing failed: server returned invalid signed bytes');\n\t\t}\n\t\tif (typeof signature !== 'string' || signature.length === 0) {\n\t\t\tthrow new Error('Devstack signing failed: server returned invalid signature');\n\t\t}\n\t\treturn {\n\t\t\tbytes: responseBytes,\n\t\t\tsignature,\n\t\t};\n\t}\n\n\toverride async signPersonalMessage(bytes: Uint8Array) {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst res = await fetch(\n\t\t\t`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.SIGN_PERSONAL_MESSAGE}`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\taddress: this.#address,\n\t\t\t\t\tbytes: toBase64(bytes),\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.json().catch(() => ({}));\n\t\t\tconst message = (body as { error?: unknown }).error;\n\t\t\tthrow new Error(\n\t\t\t\t`Devstack personal-message signing failed: ${\n\t\t\t\t\ttypeof message === 'string' ? message : res.statusText\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tconst { bytes: responseBytes, signature } = (await res.json()) as {\n\t\t\tbytes?: string;\n\t\t\tsignature?: string;\n\t\t};\n\t\tif (typeof responseBytes !== 'string' || responseBytes.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Devstack personal-message signing failed: server returned invalid signed bytes',\n\t\t\t);\n\t\t}\n\t\tif (typeof signature !== 'string' || signature.length === 0) {\n\t\t\tthrow new Error('Devstack personal-message signing failed: server returned no signature');\n\t\t}\n\t\treturn { bytes: responseBytes, signature };\n\t}\n}\n\nexport interface DevstackSignerAdapterOptions {\n\t/** Wallet-app origin (e.g. `http://localhost:9420`). Read from the\n\t * matching endpoint entry on the active manifest. */\n\tserverOrigin: string;\n\t/** Bearer token. Parse `?token=<hex>` from the manifest entry's\n\t * `pairUrl`. Omit if the wallet-app runs without auth. */\n\ttoken?: string | null;\n\t/** Override the adapter's display name. Defaults to `'Devstack'`. */\n\tname?: string;\n}\n\n/**\n * {@link SignerAdapter} that surfaces every account resolved by `devstack up`\n * (including `cliSigner`/`envSigner`/`generatedKeypair` slots) without\n * shipping their private keys into the frontend bundle. All signing happens\n * server-side via the `wallet()` plugin.\n *\n * The simplest construction uses devstack's generated `dapp-kit-config.ts`,\n * which bakes the wallet adapter wiring at codegen time — apps spread\n * `devstackDappKitConfig` into `createDAppKit(...)` and never touch the\n * adapter directly.\n *\n * To construct one manually (e.g. from a non-manifest source):\n *\n * ```ts\n * const adapter = new DevstackSignerAdapter({\n * serverOrigin: 'http://localhost:9420',\n * token: '<bearer hex>',\n * });\n * ```\n */\nexport class DevstackSignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'devstack';\n\treadonly name: string;\n\treadonly allowAutoSign = true;\n\n\t#serverOrigin: string;\n\t#authToken: string | null;\n\n\tconstructor(options: DevstackSignerAdapterOptions) {\n\t\tsuper();\n\t\ttry {\n\t\t\tnew URL(options.serverOrigin);\n\t\t} catch {\n\t\t\tthrow new Error(`DevstackSignerAdapter: invalid serverOrigin \"${options.serverOrigin}\"`);\n\t\t}\n\t\tthis.#serverOrigin = options.serverOrigin;\n\t\tthis.#authToken = options.token ?? null;\n\t\tthis.name = options.name ?? 'Devstack';\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\ttry {\n\t\t\tconst accounts = await this.#fetchAccounts();\n\t\t\tthis.setInitialAccounts(accounts);\n\t\t} catch (error) {\n\t\t\tif (error instanceof AuthError) {\n\t\t\t\tconsole.warn('[dev-wallet] devstack adapter: unauthorized — skipping account import');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconsole.warn('[dev-wallet] devstack adapter: initialization failed:', error);\n\t\t}\n\t}\n\n\toverride destroy(): void {\n\t\tthis.#authToken = null;\n\t\tsuper.destroy();\n\t}\n\n\tasync #fetchAccounts(): Promise<ManagedAccount[]> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst res = await fetch(`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.ACCOUNTS}`, {\n\t\t\theaders,\n\t\t});\n\t\tif (res.status === 401 || res.status === 403) throw new AuthError();\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`Failed to fetch devstack accounts: ${res.statusText}`);\n\t\t}\n\t\tconst { accounts } = (await res.json()) as { accounts: ServerAccountInfo[] };\n\t\treturn accounts.map((info) => {\n\t\t\tconst publicKey = publicKeyForScheme(info.publicKey, info.scheme);\n\t\t\tconst signer = new DevstackProxySigner({\n\t\t\t\taddress: info.address,\n\t\t\t\tpublicKey,\n\t\t\t\tscheme: info.scheme,\n\t\t\t\tserverOrigin: this.#serverOrigin,\n\t\t\t\tauthToken: this.#authToken,\n\t\t\t});\n\t\t\treturn buildManagedAccount(signer, info.address, info.name, DEVSTACK_WALLET_FEATURES);\n\t\t});\n\t}\n}\n\n/**\n * Pull the bearer token off a paired URL produced by the `wallet()`\n * plugin. Returns `null` if the input is undefined, malformed, or\n * carries a `<redacted>` placeholder (the manifest's pairUrl carries\n * the redacted form; the real token lives in a sibling 0o600 file the\n * consumer reads separately).\n *\n * The token rides in the URL fragment as `#token=<hex>`.\n */\nexport function parseDevstackToken(pairedUrl: string | undefined): string | null {\n\tif (pairedUrl === undefined) return null;\n\ttry {\n\t\tconst url = new URL(pairedUrl);\n\t\tconst hash = url.hash; // e.g. \"#token=abcd\"\n\t\tif (hash.length <= 1) return null;\n\t\tconst params = new URLSearchParams(hash.slice(1));\n\t\tconst token = params.get('token');\n\t\tif (token === null || token === '<redacted>') return null;\n\t\treturn token;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Narrow input — the only field the adapter consumes is\n * `app.wallet.{url, pairUrl}`. Codegen emits exactly this shape so\n * generated `dapp-kit-config.ts` doesn't have to fabricate placeholder\n * manifest fields (`stack.app`, `coins`, etc.) just to satisfy the\n * full `Manifest` type. Mirrors a slice of `AppManifest` from\n * `@mysten-incubation/devstack` without importing it (dev-wallet\n * doesn't depend on devstack — circular). */\nexport interface DevstackAdapterManifest {\n\tapp?: {\n\t\twallet?: {\n\t\t\turl: string;\n\t\t\tpairUrl?: string;\n\t\t};\n\t};\n}\n\n/**\n * Convenience: read the wallet-app endpoint off a devstack manifest and\n * build a configured adapter, or return `null` when the entry isn't\n * present (no `wallet(...)` in the stack, or it hasn't come up yet).\n *\n * The wallet entry's `pairUrl` carries the `#token=…` fragment used to\n * extract the bearer token. The full `Manifest` shape from\n * `@mysten-incubation/devstack` is structurally compatible with\n * {@link DevstackAdapterManifest}, so\n * `createDevstackAdapterFromManifest(devstackManifest)` typechecks\n * without a cast.\n */\nexport function createDevstackAdapterFromManifest(\n\tmanifest: DevstackAdapterManifest,\n): DevstackSignerAdapter | null {\n\tconst wallet = manifest.app?.wallet;\n\tif (wallet === undefined) return null;\n\treturn new DevstackSignerAdapter({\n\t\tserverOrigin: wallet.url,\n\t\ttoken: parseDevstackToken(wallet.pairUrl),\n\t});\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@ declare const DEVSTACK_WALLET_HTTP_PATH: {
|
|
|
4
4
|
readonly ACCOUNTS: "/api/v1/devstack/accounts";
|
|
5
5
|
readonly SIGN_TRANSACTION: "/api/v1/devstack/sign-transaction";
|
|
6
6
|
readonly SIGN_PERSONAL_MESSAGE: "/api/v1/devstack/sign-personal-message";
|
|
7
|
-
readonly EXECUTE: "/api/v1/devstack/execute";
|
|
8
7
|
};
|
|
9
8
|
type DevstackWalletHttpPathValue = (typeof DEVSTACK_WALLET_HTTP_PATH)[keyof typeof DEVSTACK_WALLET_HTTP_PATH];
|
|
10
9
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devstack-paths.d.mts","names":[],"sources":["../../src/adapters/devstack-paths.ts"],"mappings":";cAMa,yBAAA;EAAA
|
|
1
|
+
{"version":3,"file":"devstack-paths.d.mts","names":[],"sources":["../../src/adapters/devstack-paths.ts"],"mappings":";cAMa,yBAAA;EAAA;;;;;KAOD,2BAAA,WACH,yBAAA,eAAwC,yBAAyB"}
|
|
@@ -3,8 +3,7 @@ const DEVSTACK_WALLET_HTTP_PATH = {
|
|
|
3
3
|
HEALTH: "/api/v1/devstack/health",
|
|
4
4
|
ACCOUNTS: "/api/v1/devstack/accounts",
|
|
5
5
|
SIGN_TRANSACTION: "/api/v1/devstack/sign-transaction",
|
|
6
|
-
SIGN_PERSONAL_MESSAGE: "/api/v1/devstack/sign-personal-message"
|
|
7
|
-
EXECUTE: "/api/v1/devstack/execute"
|
|
6
|
+
SIGN_PERSONAL_MESSAGE: "/api/v1/devstack/sign-personal-message"
|
|
8
7
|
};
|
|
9
8
|
//#endregion
|
|
10
9
|
export { DEVSTACK_WALLET_HTTP_PATH };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devstack-paths.mjs","names":[],"sources":["../../src/adapters/devstack-paths.ts"],"sourcesContent":["// Mirror of `packages/devstack/src/plugins/wallet/protocol.ts` `WalletHttpPath`.\n// Duplicated here rather than imported because devstack already\n// (peer-)depends on `@mysten-incubation/dev-wallet` for codegen-emitted\n// wallet glue, and adding the reverse edge would close the workspace\n// cycle and break turbo's build ordering.\n\nexport const DEVSTACK_WALLET_HTTP_PATH = {\n\tHEALTH: '/api/v1/devstack/health',\n\tACCOUNTS: '/api/v1/devstack/accounts',\n\tSIGN_TRANSACTION: '/api/v1/devstack/sign-transaction',\n\tSIGN_PERSONAL_MESSAGE: '/api/v1/devstack/sign-personal-message',\n
|
|
1
|
+
{"version":3,"file":"devstack-paths.mjs","names":[],"sources":["../../src/adapters/devstack-paths.ts"],"sourcesContent":["// Mirror of `packages/devstack/src/plugins/wallet/protocol.ts` `WalletHttpPath`.\n// Duplicated here rather than imported because devstack already\n// (peer-)depends on `@mysten-incubation/dev-wallet` for codegen-emitted\n// wallet glue, and adding the reverse edge would close the workspace\n// cycle and break turbo's build ordering.\n\nexport const DEVSTACK_WALLET_HTTP_PATH = {\n\tHEALTH: '/api/v1/devstack/health',\n\tACCOUNTS: '/api/v1/devstack/accounts',\n\tSIGN_TRANSACTION: '/api/v1/devstack/sign-transaction',\n\tSIGN_PERSONAL_MESSAGE: '/api/v1/devstack/sign-personal-message',\n} as const;\n\nexport type DevstackWalletHttpPathValue =\n\t(typeof DEVSTACK_WALLET_HTTP_PATH)[keyof typeof DEVSTACK_WALLET_HTTP_PATH];\n"],"mappings":";AAMA,MAAa,4BAA4B;CACxC,QAAQ;CACR,UAAU;CACV,kBAAkB;CAClB,uBAAuB;AACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fork-relay.d.mts","names":[],"sources":["../../src/adapters/fork-relay.ts"],"mappings":";cASa,oBAAA;EAAA;;;;;;;;;;AAcb;;UAAiB,UAAA;EAAA,SACP,UAAA;EAAA,SACA,OAAA;EAAA,SACA,UAAA;EAAA;;EAAA,SAGA,QAAA;AAAA;AAKV;;AAAA,UAAiB,qBAAA;EAAA,SACP,OAAA;EAAA,SACA,KAAA;EAAA;;;EAAA,SAIA,MAAA;AAAA;AAAA,UAGO,gBAAA
|
|
1
|
+
{"version":3,"file":"fork-relay.d.mts","names":[],"sources":["../../src/adapters/fork-relay.ts"],"mappings":";cASa,oBAAA;EAAA;;;;;;;;;;AAcb;;UAAiB,UAAA;EAAA,SACP,UAAA;EAAA,SACA,OAAA;EAAA,SACA,UAAA;EAAA;;EAAA,SAGA,QAAA;AAAA;AAKV;;AAAA,UAAiB,qBAAA;EAAA,SACP,OAAA;EAAA,SACA,KAAA;EAAA;;;EAAA,SAIA,MAAA;AAAA;AAAA,UAGO,gBAAA;;;AAMF;WAFL,YAAA;EAKe;EAAA,SAHf,KAAK;AAAA;AAAA,cAGT,kBAAA,SAA2B,KAAK;EAAA,SAEpB,MAAA;cAAA,MAAA,UAChB,OAAA;AAAA;;KAQU,eAAA;EAAA,SACE,EAAA;EAAA,SAAmB,KAAA,EAAO,CAAC;AAAA;EAAA,SAC3B,EAAA;EAAA,SAAoB,KAAA;EAAA,SAAwB,MAAA;AAAA;;;;;;;AAAM;AA6BhE;;;;cAAa,SAAA;EAAA;cAIA,OAAA,EAAS,gBAAA;EAAA,IAUjB,YAAA;EAIE,SAAA,IAAa,OAAA,CAAQ,eAAA,CAAgB,UAAA;EAcrC,YAAA,CAAa,UAAA,WAAqB,OAAA,CAAQ,eAAA,CAAgB,UAAA;EAoB1D,iBAAA,CAAkB,KAAA,WAAgB,OAAA,CAAQ,eAAA,CAAgB,UAAA;EAoB1D,kBAAA,IAAsB,OAAA,CAAQ,eAAA,CAAgB,qBAAA;EApBZ;;;EAoClC,gBAAA,CACL,OAAA,UACA,MAAA,YACE,OAAA,CAAQ,eAAA,CAAgB,qBAAA;AAAA;;;;;UAyEX,iBAAA;EAAA,SACP,GAAA;IAAA,SACC,MAAA;MAAA,SACC,GAAA;MAAA,SACA,OAAA;IAAA;EAAA;EAAA,SAGF,IAAA;IA3IH;;IAAA,SA8II,OAAA;IA9IsC;;IAAA,SAiJtC,QAAA;EAAA;AAAA;;;;;;;;;iBAkCK,2BAAA,CAA4B,QAAA,EAAU,iBAAA,GAAoB,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fork-relay.mjs","names":["#serverOrigin","#authToken","#request"],"sources":["../../src/adapters/fork-relay.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n//\n// Browser-side relay for sui-fork admin RPCs. A compatible devstack\n// wallet endpoint can proxy a curated subset of the fork-control surface\n// (status read, advance-clock, advance-checkpoint, impersonation slot\n// list) over HTTP so the fork panel does not have to ship a gRPC\n// client into the browser bundle.\n\nexport const FORK_RELAY_HTTP_PATH = {\n\tSTATUS: '/api/v1/devstack/fork/status',\n\tADVANCE_CLOCK: '/api/v1/devstack/fork/advance-clock',\n\tADVANCE_CHECKPOINT: '/api/v1/devstack/fork/advance-checkpoint',\n\tIMPERSONATIONS: '/api/v1/devstack/fork/impersonations',\n} as const;\n\n/** Snapshot of the fork's current head state.\n *\n * Mirrors the body of `ForkControl.getStatus()` minus the unused\n * heartbeat fields. `clockMs` is a Unix-ms timestamp (the value\n * `clock::timestamp_ms()` returns on chain); `checkpoint` is the\n * latest sealed sequence number.\n */\nexport interface ForkStatus {\n\treadonly checkpoint: bigint;\n\treadonly clockMs: bigint;\n\treadonly autoTickMs?: number;\n\t/** Best-effort label of the upstream the fork is pointed at, e.g.\n\t * `'mainnet'` or `'testnet'`. Sourced from the devstack manifest. */\n\treadonly upstream?: string;\n}\n\n/** A single impersonation slot resolved by devstack — typically every\n * address that was passed to `Sui({fork:{impersonate:[…]}})`. */\nexport interface ForkImpersonationSlot {\n\treadonly address: string;\n\treadonly label?: string;\n\t/** Whether the wallet currently routes user-driven tx signing through\n\t * the `executeImpersonated` path for this address. The dev-wallet\n\t * server stores the toggle so it persists across page reloads. */\n\treadonly active: boolean;\n}\n\nexport interface ForkRelayOptions {\n\t/** Wallet-app origin (e.g. `http://localhost:9420`). Same value\n\t * `DevstackSignerAdapter` consumes — read from the manifest entry's\n\t * `app.wallet.url`. */\n\treadonly serverOrigin: string;\n\t/** Bearer token. Same parsing rules as `DevstackSignerAdapter`. */\n\treadonly token?: string | null;\n}\n\nclass ForkRelayHttpError extends Error {\n\tconstructor(\n\t\tpublic readonly status: number,\n\t\tmessage: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = 'ForkRelayHttpError';\n\t}\n}\n\n/** Tagged result so callers can render an inline error without throwing. */\nexport type ForkRelayResult<T> =\n\t| { readonly ok: true; readonly value: T }\n\t| { readonly ok: false; readonly error: string; readonly status?: number };\n\nfunction isForkStatusBody(\n\tvalue: unknown,\n): value is { checkpoint: string; clockMs: string; autoTickMs?: number; upstream?: string } {\n\tif (value === null || typeof value !== 'object') return false;\n\tconst v = value as Record<string, unknown>;\n\treturn typeof v.checkpoint === 'string' && typeof v.clockMs === 'string';\n}\n\nfunction isImpersonationsBody(\n\tvalue: unknown,\n): value is { slots: { address: string; label?: string; active: boolean }[] } {\n\tif (value === null || typeof value !== 'object') return false;\n\tconst slots = (value as { slots?: unknown }).slots;\n\treturn Array.isArray(slots);\n}\n\n/**\n * Thin HTTP client for the fork admin relay. Stateless — each call\n * issues a fresh `fetch`. The UI layer (`dev-wallet-fork-panel`)\n * polls `getStatus` on a low cadence and only refreshes after action\n * verbs land, so the lack of caching here is intentional.\n *\n * @example\n * const relay = new ForkRelay({ serverOrigin, token });\n * const status = await relay.getStatus();\n * if (status.ok) console.log(`clock=${status.value.clockMs}ms`);\n */\nexport class ForkRelay {\n\t#serverOrigin: string;\n\t#authToken: string | null;\n\n\tconstructor(options: ForkRelayOptions) {\n\t\ttry {\n\t\t\tnew URL(options.serverOrigin);\n\t\t} catch {\n\t\t\tthrow new Error(`ForkRelay: invalid serverOrigin \"${options.serverOrigin}\"`);\n\t\t}\n\t\tthis.#serverOrigin = options.serverOrigin;\n\t\tthis.#authToken = options.token ?? null;\n\t}\n\n\tget serverOrigin(): string {\n\t\treturn this.#serverOrigin;\n\t}\n\n\tasync getStatus(): Promise<ForkRelayResult<ForkStatus>> {\n\t\treturn this.#request('GET', FORK_RELAY_HTTP_PATH.STATUS, undefined, (body) => {\n\t\t\tif (!isForkStatusBody(body)) {\n\t\t\t\tthrow new Error('Malformed fork status response');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcheckpoint: BigInt(body.checkpoint),\n\t\t\t\tclockMs: BigInt(body.clockMs),\n\t\t\t\tautoTickMs: body.autoTickMs,\n\t\t\t\tupstream: body.upstream,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync advanceClock(durationMs: number): Promise<ForkRelayResult<ForkStatus>> {\n\t\tif (!Number.isFinite(durationMs) || durationMs <= 0 || !Number.isInteger(durationMs)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `advanceClock: durationMs must be a positive integer (got ${durationMs})`,\n\t\t\t};\n\t\t}\n\t\treturn this.#request('POST', FORK_RELAY_HTTP_PATH.ADVANCE_CLOCK, { durationMs }, (body) => {\n\t\t\tif (!isForkStatusBody(body)) {\n\t\t\t\tthrow new Error('Malformed advance-clock response');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcheckpoint: BigInt(body.checkpoint),\n\t\t\t\tclockMs: BigInt(body.clockMs),\n\t\t\t\tautoTickMs: body.autoTickMs,\n\t\t\t\tupstream: body.upstream,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync advanceCheckpoint(count: number): Promise<ForkRelayResult<ForkStatus>> {\n\t\tif (!Number.isFinite(count) || count <= 0 || !Number.isInteger(count)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `advanceCheckpoint: count must be a positive integer (got ${count})`,\n\t\t\t};\n\t\t}\n\t\treturn this.#request('POST', FORK_RELAY_HTTP_PATH.ADVANCE_CHECKPOINT, { count }, (body) => {\n\t\t\tif (!isForkStatusBody(body)) {\n\t\t\t\tthrow new Error('Malformed advance-checkpoint response');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcheckpoint: BigInt(body.checkpoint),\n\t\t\t\tclockMs: BigInt(body.clockMs),\n\t\t\t\tautoTickMs: body.autoTickMs,\n\t\t\t\tupstream: body.upstream,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync listImpersonations(): Promise<ForkRelayResult<ForkImpersonationSlot[]>> {\n\t\treturn this.#request('GET', FORK_RELAY_HTTP_PATH.IMPERSONATIONS, undefined, (body) => {\n\t\t\tif (!isImpersonationsBody(body)) {\n\t\t\t\tthrow new Error('Malformed impersonations response');\n\t\t\t}\n\t\t\treturn body.slots.map((s) => ({\n\t\t\t\taddress: s.address,\n\t\t\t\tlabel: s.label,\n\t\t\t\tactive: s.active,\n\t\t\t}));\n\t\t});\n\t}\n\n\t/** Toggle the impersonation slot identified by `address`. The server\n\t * is the source of truth — the response carries the resulting slot\n\t * list so the panel re-renders consistently. */\n\tasync setImpersonation(\n\t\taddress: string,\n\t\tactive: boolean,\n\t): Promise<ForkRelayResult<ForkImpersonationSlot[]>> {\n\t\treturn this.#request(\n\t\t\t'POST',\n\t\t\tFORK_RELAY_HTTP_PATH.IMPERSONATIONS,\n\t\t\t{ address, active },\n\t\t\t(body) => {\n\t\t\t\tif (!isImpersonationsBody(body)) {\n\t\t\t\t\tthrow new Error('Malformed impersonations response');\n\t\t\t\t}\n\t\t\t\treturn body.slots.map((s) => ({\n\t\t\t\t\taddress: s.address,\n\t\t\t\t\tlabel: s.label,\n\t\t\t\t\tactive: s.active,\n\t\t\t\t}));\n\t\t\t},\n\t\t);\n\t}\n\n\tasync #request<T>(\n\t\tmethod: 'GET' | 'POST',\n\t\tpath: string,\n\t\tbody: unknown,\n\t\tparse: (raw: unknown) => T,\n\t): Promise<ForkRelayResult<T>> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst init: RequestInit = { method, headers };\n\t\tif (method === 'POST' && body !== undefined) {\n\t\t\tinit.body = JSON.stringify(body);\n\t\t}\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await fetch(`${this.#serverOrigin}${path}`, init);\n\t\t} catch (cause) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `Network error: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t};\n\t\t}\n\t\tif (!res.ok) {\n\t\t\tconst text = await res.text().catch(() => res.statusText);\n\t\t\treturn { ok: false, error: text || res.statusText, status: res.status };\n\t\t}\n\t\tlet parsedBody: unknown;\n\t\ttry {\n\t\t\tparsedBody = await res.json();\n\t\t} catch (cause) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `Invalid JSON response: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t\tstatus: res.status,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\treturn { ok: true, value: parse(parsedBody) };\n\t\t} catch (cause) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\tstatus: res.status,\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport { ForkRelayHttpError };\n\n/** Narrow input mirroring `DevstackAdapterManifest` — enough to\n * discover the wallet endpoint + fork-mode flag without pulling in\n * the full devstack `Manifest` type (no reverse dependency edge,\n * same reasoning as `devstack-adapter.ts`). */\nexport interface ForkRelayManifest {\n\treadonly app?: {\n\t\treadonly wallet?: {\n\t\t\treadonly url: string;\n\t\t\treadonly pairUrl?: string;\n\t\t};\n\t};\n\treadonly meta?: {\n\t\t/** Devstack's `meta.runtime` is `'bundled' | 'forked'`. Only\n\t\t * `'forked'` triggers fork-controls construction. */\n\t\treadonly runtime?: string;\n\t\t/** Optional upstream label (`'mainnet'`, `'testnet'`, …) used\n\t\t * by the panel banner. */\n\t\treadonly upstream?: string;\n\t};\n}\n\n/** Parse the bearer token off the manifest's `pairUrl`. Duplicates the\n * logic in `devstack-adapter.ts` rather than importing it because the\n * fork-relay module must remain dependency-free from the adapter\n * layer (it's also consumed by codegen-emitted glue that doesn't pull\n * in the signer adapter bundle). */\nfunction tokenFromPairUrl(pairedUrl: string | undefined): string | null {\n\tif (pairedUrl === undefined) return null;\n\ttry {\n\t\tconst url = new URL(pairedUrl);\n\t\tif (url.hash.length > 1) {\n\t\t\tconst params = new URLSearchParams(url.hash.slice(1));\n\t\t\tconst fromHash = params.get('token');\n\t\t\tif (fromHash !== null && fromHash !== '<redacted>') return fromHash;\n\t\t}\n\t\tconst fromQuery = url.searchParams.get('token');\n\t\tif (fromQuery !== null && fromQuery !== '<redacted>') return fromQuery;\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Build a configured {@link ForkRelay} from a devstack manifest, or\n * `null` when fork-mode isn't active (bundled stack, no wallet entry,\n * or the manifest hasn't loaded yet).\n *\n * Codegen-emitted browser glue calls this and forwards the result to\n * `<dev-wallet-panel forkRelay={…}>`.\n */\nexport function createForkRelayFromManifest(manifest: ForkRelayManifest): ForkRelay | null {\n\tif (manifest.meta?.runtime !== 'forked') return null;\n\tconst wallet = manifest.app?.wallet;\n\tif (wallet === undefined) return null;\n\ttry {\n\t\treturn new ForkRelay({\n\t\t\tserverOrigin: wallet.url,\n\t\t\ttoken: tokenFromPairUrl(wallet.pairUrl),\n\t\t});\n\t} catch {\n\t\t// `new URL(…)` failure surfaces as a thrown Error — swallow it\n\t\t// here rather than propagating, the calling app shouldn't\n\t\t// blow up just because the manifest's wallet URL is malformed.\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fork-relay.mjs","names":["#serverOrigin","#authToken","#request"],"sources":["../../src/adapters/fork-relay.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n//\n// Browser-side relay for sui-fork admin RPCs. A compatible devstack\n// wallet endpoint can proxy a curated subset of the fork-control surface\n// (status read, advance-clock, advance-checkpoint, impersonation slot\n// list) over HTTP so the fork panel does not have to ship a gRPC\n// client into the browser bundle.\n\nexport const FORK_RELAY_HTTP_PATH = {\n\tSTATUS: '/api/v1/devstack/fork/status',\n\tADVANCE_CLOCK: '/api/v1/devstack/fork/advance-clock',\n\tADVANCE_CHECKPOINT: '/api/v1/devstack/fork/advance-checkpoint',\n\tIMPERSONATIONS: '/api/v1/devstack/fork/impersonations',\n} as const;\n\n/** Snapshot of the fork's current head state.\n *\n * Mirrors the body of `ForkControl.getStatus()` minus the unused\n * heartbeat fields. `clockMs` is a Unix-ms timestamp (the value\n * `clock::timestamp_ms()` returns on chain); `checkpoint` is the\n * latest sealed sequence number.\n */\nexport interface ForkStatus {\n\treadonly checkpoint: bigint;\n\treadonly clockMs: bigint;\n\treadonly autoTickMs?: number;\n\t/** Best-effort label of the upstream the fork is pointed at, e.g.\n\t * `'mainnet'` or `'testnet'`. Sourced from the devstack manifest. */\n\treadonly upstream?: string;\n}\n\n/** A single impersonation slot resolved by devstack — typically every\n * address that was passed to `Sui({fork:{impersonate:[…]}})`. */\nexport interface ForkImpersonationSlot {\n\treadonly address: string;\n\treadonly label?: string;\n\t/** Whether the wallet currently routes user-driven tx signing through\n\t * the `executeImpersonated` path for this address. The dev-wallet\n\t * server stores the toggle so it persists across page reloads. */\n\treadonly active: boolean;\n}\n\nexport interface ForkRelayOptions {\n\t/** Wallet-app origin (e.g. `http://localhost:9420`). Same value\n\t * `DevstackSignerAdapter` consumes — read from the manifest entry's\n\t * `app.wallet.url`. */\n\treadonly serverOrigin: string;\n\t/** Bearer token. Same parsing rules as `DevstackSignerAdapter`. */\n\treadonly token?: string | null;\n}\n\nclass ForkRelayHttpError extends Error {\n\tconstructor(\n\t\tpublic readonly status: number,\n\t\tmessage: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = 'ForkRelayHttpError';\n\t}\n}\n\n/** Tagged result so callers can render an inline error without throwing. */\nexport type ForkRelayResult<T> =\n\t| { readonly ok: true; readonly value: T }\n\t| { readonly ok: false; readonly error: string; readonly status?: number };\n\nfunction isForkStatusBody(\n\tvalue: unknown,\n): value is { checkpoint: string; clockMs: string; autoTickMs?: number; upstream?: string } {\n\tif (value === null || typeof value !== 'object') return false;\n\tconst v = value as Record<string, unknown>;\n\treturn typeof v.checkpoint === 'string' && typeof v.clockMs === 'string';\n}\n\nfunction isImpersonationsBody(\n\tvalue: unknown,\n): value is { slots: { address: string; label?: string; active: boolean }[] } {\n\tif (value === null || typeof value !== 'object') return false;\n\tconst slots = (value as { slots?: unknown }).slots;\n\treturn Array.isArray(slots);\n}\n\n/**\n * Thin HTTP client for the fork admin relay. Stateless — each call\n * issues a fresh `fetch`. The UI layer (`dev-wallet-fork-panel`)\n * polls `getStatus` on a low cadence and only refreshes after action\n * verbs land, so the lack of caching here is intentional.\n *\n * @example\n * const relay = new ForkRelay({ serverOrigin, token });\n * const status = await relay.getStatus();\n * if (status.ok) console.log(`clock=${status.value.clockMs}ms`);\n */\nexport class ForkRelay {\n\t#serverOrigin: string;\n\t#authToken: string | null;\n\n\tconstructor(options: ForkRelayOptions) {\n\t\ttry {\n\t\t\tnew URL(options.serverOrigin);\n\t\t} catch {\n\t\t\tthrow new Error(`ForkRelay: invalid serverOrigin \"${options.serverOrigin}\"`);\n\t\t}\n\t\tthis.#serverOrigin = options.serverOrigin;\n\t\tthis.#authToken = options.token ?? null;\n\t}\n\n\tget serverOrigin(): string {\n\t\treturn this.#serverOrigin;\n\t}\n\n\tasync getStatus(): Promise<ForkRelayResult<ForkStatus>> {\n\t\treturn this.#request('GET', FORK_RELAY_HTTP_PATH.STATUS, undefined, (body) => {\n\t\t\tif (!isForkStatusBody(body)) {\n\t\t\t\tthrow new Error('Malformed fork status response');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcheckpoint: BigInt(body.checkpoint),\n\t\t\t\tclockMs: BigInt(body.clockMs),\n\t\t\t\tautoTickMs: body.autoTickMs,\n\t\t\t\tupstream: body.upstream,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync advanceClock(durationMs: number): Promise<ForkRelayResult<ForkStatus>> {\n\t\tif (!Number.isFinite(durationMs) || durationMs <= 0 || !Number.isInteger(durationMs)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `advanceClock: durationMs must be a positive integer (got ${durationMs})`,\n\t\t\t};\n\t\t}\n\t\treturn this.#request('POST', FORK_RELAY_HTTP_PATH.ADVANCE_CLOCK, { durationMs }, (body) => {\n\t\t\tif (!isForkStatusBody(body)) {\n\t\t\t\tthrow new Error('Malformed advance-clock response');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcheckpoint: BigInt(body.checkpoint),\n\t\t\t\tclockMs: BigInt(body.clockMs),\n\t\t\t\tautoTickMs: body.autoTickMs,\n\t\t\t\tupstream: body.upstream,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync advanceCheckpoint(count: number): Promise<ForkRelayResult<ForkStatus>> {\n\t\tif (!Number.isFinite(count) || count <= 0 || !Number.isInteger(count)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `advanceCheckpoint: count must be a positive integer (got ${count})`,\n\t\t\t};\n\t\t}\n\t\treturn this.#request('POST', FORK_RELAY_HTTP_PATH.ADVANCE_CHECKPOINT, { count }, (body) => {\n\t\t\tif (!isForkStatusBody(body)) {\n\t\t\t\tthrow new Error('Malformed advance-checkpoint response');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcheckpoint: BigInt(body.checkpoint),\n\t\t\t\tclockMs: BigInt(body.clockMs),\n\t\t\t\tautoTickMs: body.autoTickMs,\n\t\t\t\tupstream: body.upstream,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync listImpersonations(): Promise<ForkRelayResult<ForkImpersonationSlot[]>> {\n\t\treturn this.#request('GET', FORK_RELAY_HTTP_PATH.IMPERSONATIONS, undefined, (body) => {\n\t\t\tif (!isImpersonationsBody(body)) {\n\t\t\t\tthrow new Error('Malformed impersonations response');\n\t\t\t}\n\t\t\treturn body.slots.map((s) => ({\n\t\t\t\taddress: s.address,\n\t\t\t\tlabel: s.label,\n\t\t\t\tactive: s.active,\n\t\t\t}));\n\t\t});\n\t}\n\n\t/** Toggle the impersonation slot identified by `address`. The server\n\t * is the source of truth — the response carries the resulting slot\n\t * list so the panel re-renders consistently. */\n\tasync setImpersonation(\n\t\taddress: string,\n\t\tactive: boolean,\n\t): Promise<ForkRelayResult<ForkImpersonationSlot[]>> {\n\t\treturn this.#request(\n\t\t\t'POST',\n\t\t\tFORK_RELAY_HTTP_PATH.IMPERSONATIONS,\n\t\t\t{ address, active },\n\t\t\t(body) => {\n\t\t\t\tif (!isImpersonationsBody(body)) {\n\t\t\t\t\tthrow new Error('Malformed impersonations response');\n\t\t\t\t}\n\t\t\t\treturn body.slots.map((s) => ({\n\t\t\t\t\taddress: s.address,\n\t\t\t\t\tlabel: s.label,\n\t\t\t\t\tactive: s.active,\n\t\t\t\t}));\n\t\t\t},\n\t\t);\n\t}\n\n\tasync #request<T>(\n\t\tmethod: 'GET' | 'POST',\n\t\tpath: string,\n\t\tbody: unknown,\n\t\tparse: (raw: unknown) => T,\n\t): Promise<ForkRelayResult<T>> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\t\tif (this.#authToken !== null) {\n\t\t\theaders['Authorization'] = `Bearer ${this.#authToken}`;\n\t\t}\n\t\tconst init: RequestInit = { method, headers };\n\t\tif (method === 'POST' && body !== undefined) {\n\t\t\tinit.body = JSON.stringify(body);\n\t\t}\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await fetch(`${this.#serverOrigin}${path}`, init);\n\t\t} catch (cause) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `Network error: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t};\n\t\t}\n\t\tif (!res.ok) {\n\t\t\tconst text = await res.text().catch(() => res.statusText);\n\t\t\treturn { ok: false, error: text || res.statusText, status: res.status };\n\t\t}\n\t\tlet parsedBody: unknown;\n\t\ttry {\n\t\t\tparsedBody = await res.json();\n\t\t} catch (cause) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `Invalid JSON response: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t\tstatus: res.status,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\treturn { ok: true, value: parse(parsedBody) };\n\t\t} catch (cause) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\tstatus: res.status,\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport { ForkRelayHttpError };\n\n/** Narrow input mirroring `DevstackAdapterManifest` — enough to\n * discover the wallet endpoint + fork-mode flag without pulling in\n * the full devstack `Manifest` type (no reverse dependency edge,\n * same reasoning as `devstack-adapter.ts`). */\nexport interface ForkRelayManifest {\n\treadonly app?: {\n\t\treadonly wallet?: {\n\t\t\treadonly url: string;\n\t\t\treadonly pairUrl?: string;\n\t\t};\n\t};\n\treadonly meta?: {\n\t\t/** Devstack's `meta.runtime` is `'bundled' | 'forked'`. Only\n\t\t * `'forked'` triggers fork-controls construction. */\n\t\treadonly runtime?: string;\n\t\t/** Optional upstream label (`'mainnet'`, `'testnet'`, …) used\n\t\t * by the panel banner. */\n\t\treadonly upstream?: string;\n\t};\n}\n\n/** Parse the bearer token off the manifest's `pairUrl`. Duplicates the\n * logic in `devstack-adapter.ts` rather than importing it because the\n * fork-relay module must remain dependency-free from the adapter\n * layer (it's also consumed by codegen-emitted glue that doesn't pull\n * in the signer adapter bundle). */\nfunction tokenFromPairUrl(pairedUrl: string | undefined): string | null {\n\tif (pairedUrl === undefined) return null;\n\ttry {\n\t\tconst url = new URL(pairedUrl);\n\t\tif (url.hash.length > 1) {\n\t\t\tconst params = new URLSearchParams(url.hash.slice(1));\n\t\t\tconst fromHash = params.get('token');\n\t\t\tif (fromHash !== null && fromHash !== '<redacted>') return fromHash;\n\t\t}\n\t\tconst fromQuery = url.searchParams.get('token');\n\t\tif (fromQuery !== null && fromQuery !== '<redacted>') return fromQuery;\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Build a configured {@link ForkRelay} from a devstack manifest, or\n * `null` when fork-mode isn't active (bundled stack, no wallet entry,\n * or the manifest hasn't loaded yet).\n *\n * Codegen-emitted browser glue calls this and forwards the result to\n * `<dev-wallet-panel forkRelay={…}>`.\n */\nexport function createForkRelayFromManifest(manifest: ForkRelayManifest): ForkRelay | null {\n\tif (manifest.meta?.runtime !== 'forked') return null;\n\tconst wallet = manifest.app?.wallet;\n\tif (wallet === undefined) return null;\n\ttry {\n\t\treturn new ForkRelay({\n\t\t\tserverOrigin: wallet.url,\n\t\t\ttoken: tokenFromPairUrl(wallet.pairUrl),\n\t\t});\n\t} catch {\n\t\t// `new URL(…)` failure surfaces as a thrown Error — swallow it\n\t\t// here rather than propagating, the calling app shouldn't\n\t\t// blow up just because the manifest's wallet URL is malformed.\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idb-store.mjs","names":["#dbName","#storeName","#withTx","#open","#db"],"sources":["../../src/adapters/idb-store.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Minimal IndexedDB key-value store replacing the `idb-keyval` package.\n *\n * The database connection is opened lazily on first use and reused for all\n * subsequent operations.\n */\nexport class IDBStore {\n\t#dbName: string;\n\t#storeName: string;\n\t#db: Promise<IDBDatabase> | null = null;\n\n\tconstructor(dbName: string, storeName: string) {\n\t\tthis.#dbName = dbName;\n\t\tthis.#storeName = storeName;\n\t}\n\n\tget<T>(key: IDBValidKey): Promise<T | undefined> {\n\t\treturn this.#withTx('readonly', (s) => s.get(key) as IDBRequest<T | undefined>);\n\t}\n\n\tasync set(key: IDBValidKey, value: unknown): Promise<void> {\n\t\tawait this.#withTx('readwrite', (s) => s.put(value, key));\n\t}\n\n\tdel(key: IDBValidKey): Promise<void> {\n\t\treturn this.#withTx('readwrite', (s) => s.delete(key) as IDBRequest<void>);\n\t}\n\n\tentries<K extends IDBValidKey, V>(): Promise<[K, V][]> {\n\t\treturn this.#open().then(\n\t\t\t(db) =>\n\t\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\t\tconst tx = db.transaction(this.#storeName, 'readonly');\n\t\t\t\t\tconst objectStore = tx.objectStore(this.#storeName);\n\t\t\t\t\tconst results: [K, V][] = [];\n\t\t\t\t\tconst cursor = objectStore.openCursor();\n\t\t\t\t\tcursor.onsuccess = () => {\n\t\t\t\t\t\tconst c = cursor.result;\n\t\t\t\t\t\tif (c) {\n\t\t\t\t\t\t\tresults.push([c.key as K, c.value as V]);\n\t\t\t\t\t\t\tc.continue();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\ttx.oncomplete = () => resolve(results);\n\t\t\t\t\ttx.onerror = () => reject(tx.error);\n\t\t\t\t}),\n\t\t);\n\t}\n\n\t#open(): Promise<IDBDatabase> {\n\t\tif (!this.#db) {\n\t\t\tthis.#db = new Promise((resolve, reject) => {\n\t\t\t\tconst request = indexedDB.open(this.#dbName);\n\t\t\t\trequest.onupgradeneeded = () => {\n\t\t\t\t\tif (!request.result.objectStoreNames.contains(this.#storeName)) {\n\t\t\t\t\t\trequest.result.createObjectStore(this.#storeName);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\trequest.onsuccess = () => resolve(request.result);\n\t\t\t\trequest.onerror = () => {\n\t\t\t\t\tthis.#db = null;\n\t\t\t\t\treject(request.error);\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t\treturn this.#db;\n\t}\n\n\t#withTx<T>(\n\t\tmode: IDBTransactionMode,\n\t\tfn: (objectStore: IDBObjectStore) => IDBRequest<T>,\n\t): Promise<T> {\n\t\treturn this.#open().then(\n\t\t\t(db) =>\n\t\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\t\tconst tx = db.transaction(this.#storeName, mode);\n\t\t\t\t\tconst req = fn(tx.objectStore(this.#storeName));\n\t\t\t\t\ttx.oncomplete = () => resolve(req.result);\n\t\t\t\t\ttx.onerror = () => reject(tx.error);\n\t\t\t\t\ttx.onabort = () => reject(tx.error);\n\t\t\t\t}),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;AASA,IAAa,WAAb,MAAsB;CACrB;CACA;CACA,MAAmC;CAEnC,YAAY,QAAgB,WAAmB;
|
|
1
|
+
{"version":3,"file":"idb-store.mjs","names":["#dbName","#storeName","#withTx","#open","#db"],"sources":["../../src/adapters/idb-store.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Minimal IndexedDB key-value store replacing the `idb-keyval` package.\n *\n * The database connection is opened lazily on first use and reused for all\n * subsequent operations.\n */\nexport class IDBStore {\n\t#dbName: string;\n\t#storeName: string;\n\t#db: Promise<IDBDatabase> | null = null;\n\n\tconstructor(dbName: string, storeName: string) {\n\t\tthis.#dbName = dbName;\n\t\tthis.#storeName = storeName;\n\t}\n\n\tget<T>(key: IDBValidKey): Promise<T | undefined> {\n\t\treturn this.#withTx('readonly', (s) => s.get(key) as IDBRequest<T | undefined>);\n\t}\n\n\tasync set(key: IDBValidKey, value: unknown): Promise<void> {\n\t\tawait this.#withTx('readwrite', (s) => s.put(value, key));\n\t}\n\n\tdel(key: IDBValidKey): Promise<void> {\n\t\treturn this.#withTx('readwrite', (s) => s.delete(key) as IDBRequest<void>);\n\t}\n\n\tentries<K extends IDBValidKey, V>(): Promise<[K, V][]> {\n\t\treturn this.#open().then(\n\t\t\t(db) =>\n\t\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\t\tconst tx = db.transaction(this.#storeName, 'readonly');\n\t\t\t\t\tconst objectStore = tx.objectStore(this.#storeName);\n\t\t\t\t\tconst results: [K, V][] = [];\n\t\t\t\t\tconst cursor = objectStore.openCursor();\n\t\t\t\t\tcursor.onsuccess = () => {\n\t\t\t\t\t\tconst c = cursor.result;\n\t\t\t\t\t\tif (c) {\n\t\t\t\t\t\t\tresults.push([c.key as K, c.value as V]);\n\t\t\t\t\t\t\tc.continue();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\ttx.oncomplete = () => resolve(results);\n\t\t\t\t\ttx.onerror = () => reject(tx.error);\n\t\t\t\t}),\n\t\t);\n\t}\n\n\t#open(): Promise<IDBDatabase> {\n\t\tif (!this.#db) {\n\t\t\tthis.#db = new Promise((resolve, reject) => {\n\t\t\t\tconst request = indexedDB.open(this.#dbName);\n\t\t\t\trequest.onupgradeneeded = () => {\n\t\t\t\t\tif (!request.result.objectStoreNames.contains(this.#storeName)) {\n\t\t\t\t\t\trequest.result.createObjectStore(this.#storeName);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\trequest.onsuccess = () => resolve(request.result);\n\t\t\t\trequest.onerror = () => {\n\t\t\t\t\tthis.#db = null;\n\t\t\t\t\treject(request.error);\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t\treturn this.#db;\n\t}\n\n\t#withTx<T>(\n\t\tmode: IDBTransactionMode,\n\t\tfn: (objectStore: IDBObjectStore) => IDBRequest<T>,\n\t): Promise<T> {\n\t\treturn this.#open().then(\n\t\t\t(db) =>\n\t\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\t\tconst tx = db.transaction(this.#storeName, mode);\n\t\t\t\t\tconst req = fn(tx.objectStore(this.#storeName));\n\t\t\t\t\ttx.oncomplete = () => resolve(req.result);\n\t\t\t\t\ttx.onerror = () => reject(tx.error);\n\t\t\t\t\ttx.onabort = () => reject(tx.error);\n\t\t\t\t}),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;AASA,IAAa,WAAb,MAAsB;CACrB;CACA;CACA,MAAmC;CAEnC,YAAY,QAAgB,WAAmB;EAC9C,KAAKA,UAAU;EACf,KAAKC,aAAa;CACnB;CAEA,IAAO,KAA0C;EAChD,OAAO,KAAKC,QAAQ,aAAa,MAAM,EAAE,IAAI,GAAG,CAA8B;CAC/E;CAEA,MAAM,IAAI,KAAkB,OAA+B;EAC1D,MAAM,KAAKA,QAAQ,cAAc,MAAM,EAAE,IAAI,OAAO,GAAG,CAAC;CACzD;CAEA,IAAI,KAAiC;EACpC,OAAO,KAAKA,QAAQ,cAAc,MAAM,EAAE,OAAO,GAAG,CAAqB;CAC1E;CAEA,UAAuD;EACtD,OAAO,KAAKC,MAAM,CAAC,CAAC,MAClB,OACA,IAAI,SAAS,SAAS,WAAW;GAChC,MAAM,KAAK,GAAG,YAAY,KAAKF,YAAY,UAAU;GACrD,MAAM,cAAc,GAAG,YAAY,KAAKA,UAAU;GAClD,MAAM,UAAoB,CAAC;GAC3B,MAAM,SAAS,YAAY,WAAW;GACtC,OAAO,kBAAkB;IACxB,MAAM,IAAI,OAAO;IACjB,IAAI,GAAG;KACN,QAAQ,KAAK,CAAC,EAAE,KAAU,EAAE,KAAU,CAAC;KACvC,EAAE,SAAS;IACZ;GACD;GACA,GAAG,mBAAmB,QAAQ,OAAO;GACrC,GAAG,gBAAgB,OAAO,GAAG,KAAK;EACnC,CAAC,CACH;CACD;CAEA,QAA8B;EAC7B,IAAI,CAAC,KAAKG,KACT,KAAKA,MAAM,IAAI,SAAS,SAAS,WAAW;GAC3C,MAAM,UAAU,UAAU,KAAK,KAAKJ,OAAO;GAC3C,QAAQ,wBAAwB;IAC/B,IAAI,CAAC,QAAQ,OAAO,iBAAiB,SAAS,KAAKC,UAAU,GAC5D,QAAQ,OAAO,kBAAkB,KAAKA,UAAU;GAElD;GACA,QAAQ,kBAAkB,QAAQ,QAAQ,MAAM;GAChD,QAAQ,gBAAgB;IACvB,KAAKG,MAAM;IACX,OAAO,QAAQ,KAAK;GACrB;EACD,CAAC;EAEF,OAAO,KAAKA;CACb;CAEA,QACC,MACA,IACa;EACb,OAAO,KAAKD,MAAM,CAAC,CAAC,MAClB,OACA,IAAI,SAAS,SAAS,WAAW;GAChC,MAAM,KAAK,GAAG,YAAY,KAAKF,YAAY,IAAI;GAC/C,MAAM,MAAM,GAAG,GAAG,YAAY,KAAKA,UAAU,CAAC;GAC9C,GAAG,mBAAmB,QAAQ,IAAI,MAAM;GACxC,GAAG,gBAAgB,OAAO,GAAG,KAAK;GAClC,GAAG,gBAAgB,OAAO,GAAG,KAAK;EACnC,CAAC,CACH;CACD;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-adapter.d.mts","names":[],"sources":["../../src/adapters/in-memory-adapter.ts"],"mappings":";;;;cASa,qBAAA,SAA8B,iBAAA;EAAA,SACjC,EAAA;EAAA,SACA,IAAA;EAEH,UAAA,
|
|
1
|
+
{"version":3,"file":"in-memory-adapter.d.mts","names":[],"sources":["../../src/adapters/in-memory-adapter.ts"],"mappings":";;;;cASa,qBAAA,SAA8B,iBAAA;EAAA,SACjC,EAAA;EAAA,SACA,IAAA;EAEH,UAAA,IAAc,OAAA;EAId,aAAA,CAAc,OAAA,GAAU,oBAAA,GAAuB,OAAA,CAAQ,cAAA;EAUvD,aAAA,CAAc,OAAA,EAAS,oBAAA,GAAuB,OAAA,CAAQ,cAAA;EAgBtD,aAAA,CAAc,OAAA,UAAiB,KAAA,WAAgB,OAAA;EAI/C,aAAA,CAAc,OAAA,WAAkB,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-adapter.mjs","names":[],"sources":["../../src/adapters/in-memory-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\n\nimport type { CreateAccountOptions, ImportAccountOptions, ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\n\nexport class InMemorySignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'in-memory';\n\treadonly name = 'In-Memory Signer';\n\n\tasync initialize(): Promise<void> {\n\t\t// No-op for in-memory adapter\n\t}\n\n\tasync createAccount(options?: CreateAccountOptions): Promise<ManagedAccount> {\n\t\tconst keypair = new Ed25519Keypair();\n\t\tconst address = keypair.getPublicKey().toSuiAddress();\n\t\tconst label = options?.label ?? this.getDefaultLabel();\n\n\t\tconst managedAccount = buildManagedAccount(keypair, address, label);\n\t\tthis.addAccount(managedAccount);\n\t\treturn managedAccount;\n\t}\n\n\tasync importAccount(options: ImportAccountOptions): Promise<ManagedAccount> {\n\t\tconst signer = options.signer;\n\t\tif (!signer) {\n\t\t\tthrow new Error('In-memory adapter requires a signer to import');\n\t\t}\n\t\tconst address = signer.toSuiAddress();\n\n\t\tconst existing = this.getAccount(address);\n\t\tif (existing) return existing;\n\n\t\tconst label = options.label ?? this.getDefaultLabel();\n\t\tconst managedAccount = buildManagedAccount(signer, address, label);\n\t\tthis.addAccount(managedAccount);\n\t\treturn managedAccount;\n\t}\n\n\tasync renameAccount(address: string, label: string): Promise<boolean> {\n\t\treturn this._performRename(address, label);\n\t}\n\n\tasync removeAccount(address: string): Promise<boolean> {\n\t\treturn this.removeAccountByAddress(address);\n\t}\n}\n"],"mappings":";;;;AASA,IAAa,wBAAb,cAA2C,kBAAkB;;;YAC9C;cACE;;CAEhB,MAAM,aAA4B;
|
|
1
|
+
{"version":3,"file":"in-memory-adapter.mjs","names":[],"sources":["../../src/adapters/in-memory-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\n\nimport type { CreateAccountOptions, ImportAccountOptions, ManagedAccount } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\n\nexport class InMemorySignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'in-memory';\n\treadonly name = 'In-Memory Signer';\n\n\tasync initialize(): Promise<void> {\n\t\t// No-op for in-memory adapter\n\t}\n\n\tasync createAccount(options?: CreateAccountOptions): Promise<ManagedAccount> {\n\t\tconst keypair = new Ed25519Keypair();\n\t\tconst address = keypair.getPublicKey().toSuiAddress();\n\t\tconst label = options?.label ?? this.getDefaultLabel();\n\n\t\tconst managedAccount = buildManagedAccount(keypair, address, label);\n\t\tthis.addAccount(managedAccount);\n\t\treturn managedAccount;\n\t}\n\n\tasync importAccount(options: ImportAccountOptions): Promise<ManagedAccount> {\n\t\tconst signer = options.signer;\n\t\tif (!signer) {\n\t\t\tthrow new Error('In-memory adapter requires a signer to import');\n\t\t}\n\t\tconst address = signer.toSuiAddress();\n\n\t\tconst existing = this.getAccount(address);\n\t\tif (existing) return existing;\n\n\t\tconst label = options.label ?? this.getDefaultLabel();\n\t\tconst managedAccount = buildManagedAccount(signer, address, label);\n\t\tthis.addAccount(managedAccount);\n\t\treturn managedAccount;\n\t}\n\n\tasync renameAccount(address: string, label: string): Promise<boolean> {\n\t\treturn this._performRename(address, label);\n\t}\n\n\tasync removeAccount(address: string): Promise<boolean> {\n\t\treturn this.removeAccountByAddress(address);\n\t}\n}\n"],"mappings":";;;;AASA,IAAa,wBAAb,cAA2C,kBAAkB;;;YAC9C;cACE;;CAEhB,MAAM,aAA4B,CAElC;CAEA,MAAM,cAAc,SAAyD;EAC5E,MAAM,UAAU,IAAI,eAAe;EAInC,MAAM,iBAAiB,oBAAoB,SAH3B,QAAQ,aAAa,CAAC,CAAC,aAGa,GAFtC,SAAS,SAAS,KAAK,gBAAgB,CAEa;EAClE,KAAK,WAAW,cAAc;EAC9B,OAAO;CACR;CAEA,MAAM,cAAc,SAAwD;EAC3E,MAAM,SAAS,QAAQ;EACvB,IAAI,CAAC,QACJ,MAAM,IAAI,MAAM,+CAA+C;EAEhE,MAAM,UAAU,OAAO,aAAa;EAEpC,MAAM,WAAW,KAAK,WAAW,OAAO;EACxC,IAAI,UAAU,OAAO;EAGrB,MAAM,iBAAiB,oBAAoB,QAAQ,SADrC,QAAQ,SAAS,KAAK,gBAAgB,CACa;EACjE,KAAK,WAAW,cAAc;EAC9B,OAAO;CACR;CAEA,MAAM,cAAc,SAAiB,OAAiC;EACrE,OAAO,KAAK,eAAe,SAAS,KAAK;CAC1C;CAEA,MAAM,cAAc,SAAmC;EACtD,OAAO,KAAK,uBAAuB,OAAO;CAC3C;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passkey-adapter.d.mts","names":[],"sources":["../../src/adapters/passkey-adapter.ts"],"mappings":";;;;;;;AAgCA;;;;;cAAa,oBAAA,SAA6B,iBAAA;EAAA;WAChC,EAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;cAKG,OAAA;IAAY,MAAA;IAAiB,SAAA;IAAoB,QAAA,GAAW,eAAA;EAAA;EAiBlE,UAAA,
|
|
1
|
+
{"version":3,"file":"passkey-adapter.d.mts","names":[],"sources":["../../src/adapters/passkey-adapter.ts"],"mappings":";;;;;;;AAgCA;;;;;cAAa,oBAAA,SAA6B,iBAAA;EAAA;WAChC,EAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;cAKG,OAAA;IAAY,MAAA;IAAiB,SAAA;IAAoB,QAAA,GAAW,eAAA;EAAA;EAiBlE,UAAA,IAAc,OAAA;EAAA,UAsBD,eAAA;EAIb,aAAA,CAAc,OAAA,GAAU,oBAAA,GAAoB,OAAA,CAAA,cAAA;EAY5C,aAAA,CAAc,OAAA,UAAiB,KAAA,WAAgB,OAAA;EAM/C,aAAA,CAAc,OAAA,WAAkB,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passkey-adapter.mjs","names":["#store","#provider","#getProvider","#saveMeta"],"sources":["../../src/adapters/passkey-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { PasskeyKeypair } from '@mysten/sui/keypairs/passkey';\nimport type { PasskeyProvider } from '@mysten/sui/keypairs/passkey';\n\nimport type { CreateAccountOptions } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\nimport { IDBStore } from './idb-store.js';\n\n/** Metadata stored in IndexedDB for each passkey account. */\ninterface StoredPasskeyMeta {\n\taddress: string;\n\tlabel: string;\n\t/** Compressed secp256r1 public key (33 bytes, stored as number array). */\n\tpublicKeyBytes: number[];\n\t/** WebAuthn credential ID (stored as number array). Used to constrain credential selection during signing. */\n\tcredentialId?: number[];\n}\n\nconst DEFAULT_DB_NAME = 'dev-wallet-passkey';\nconst DEFAULT_STORE_NAME = 'accounts';\nconst META_KEY = '__passkey_accounts__';\n\n/**\n * Signer adapter backed by WebAuthn passkeys. Each signing operation triggers a\n * browser biometric/PIN prompt. Account metadata is persisted in IndexedDB;\n * private keys are managed by the browser/OS and never enter JavaScript.\n *\n * Browser only — requires `navigator.credentials` and `indexedDB`.\n */\nexport class PasskeySignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'passkey';\n\treadonly name = 'Passkey Signer';\n\treadonly allowAutoSign = false;\n\n\t#store: IDBStore;\n\t#provider: PasskeyProvider | null;\n\n\tconstructor(options?: { dbName?: string; storeName?: string; provider?: PasskeyProvider }) {\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\t// Allow injecting a custom provider (useful for testing)\n\t\tthis.#provider = options?.provider ?? null;\n\t}\n\n\t#getProvider(): PasskeyProvider {\n\t\tif (!this.#provider) {\n\t\t\tthrow new Error('PasskeySignerAdapter not initialized. Call initialize() first.');\n\t\t}\n\t\treturn this.#provider;\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tif (!this.#provider) {\n\t\t\tconst { BrowserPasskeyProvider } = await import('@mysten/sui/keypairs/passkey');\n\t\t\tthis.#provider = new BrowserPasskeyProvider('Dev Wallet Passkey', {\n\t\t\t\trp: { id: globalThis.location?.hostname },\n\t\t\t});\n\t\t}\n\n\t\tconst stored = await this.#store.get<StoredPasskeyMeta[]>(META_KEY);\n\t\tif (!stored) return;\n\n\t\tconst provider = this.#getProvider();\n\t\tthis.setInitialAccounts(\n\t\t\tstored.map((meta) => {\n\t\t\t\tconst publicKeyBytes = new Uint8Array(meta.publicKeyBytes);\n\t\t\t\tconst credentialId = meta.credentialId ? new Uint8Array(meta.credentialId) : undefined;\n\t\t\t\tconst signer = new PasskeyKeypair(publicKeyBytes, provider, credentialId);\n\t\t\t\treturn buildManagedAccount(signer, meta.address, meta.label);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprotected override getDefaultLabel(): string {\n\t\treturn `Passkey Account ${this.getAccounts().length + 1}`;\n\t}\n\n\tasync createAccount(options?: CreateAccountOptions) {\n\t\tconst signer = await PasskeyKeypair.getPasskeyInstance(this.#getProvider());\n\t\tconst address = signer.toSuiAddress();\n\t\tconst label = options?.label ?? this.getDefaultLabel();\n\n\t\tconst managedAccount = buildManagedAccount(signer, address, label);\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\t\tawait this.#saveMeta();\n\t\treturn true;\n\t}\n\n\tasync #saveMeta(): Promise<void> {\n\t\tconst meta: StoredPasskeyMeta[] = this.getAccounts().map((a) => {\n\t\t\tconst credentialId = (a.signer as PasskeyKeypair).getCredentialId?.();\n\t\t\treturn {\n\t\t\t\taddress: a.address,\n\t\t\t\tlabel: a.label,\n\t\t\t\tpublicKeyBytes: [...a.signer.getPublicKey().toRawBytes()],\n\t\t\t\t...(credentialId && { credentialId: [...credentialId] }),\n\t\t\t};\n\t\t});\n\t\tawait this.#store.set(META_KEY, meta);\n\t}\n}\n"],"mappings":";;;;;AAqBA,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,WAAW;;;;;;;;AASjB,IAAa,uBAAb,cAA0C,kBAAkB;CAK3D;CACA;CAEA,YAAY,SAA+E;
|
|
1
|
+
{"version":3,"file":"passkey-adapter.mjs","names":["#store","#provider","#getProvider","#saveMeta"],"sources":["../../src/adapters/passkey-adapter.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { PasskeyKeypair } from '@mysten/sui/keypairs/passkey';\nimport type { PasskeyProvider } from '@mysten/sui/keypairs/passkey';\n\nimport type { CreateAccountOptions } from '../types.js';\nimport { BaseSignerAdapter } from './base-adapter.js';\nimport { buildManagedAccount } from './build-managed-account.js';\nimport { IDBStore } from './idb-store.js';\n\n/** Metadata stored in IndexedDB for each passkey account. */\ninterface StoredPasskeyMeta {\n\taddress: string;\n\tlabel: string;\n\t/** Compressed secp256r1 public key (33 bytes, stored as number array). */\n\tpublicKeyBytes: number[];\n\t/** WebAuthn credential ID (stored as number array). Used to constrain credential selection during signing. */\n\tcredentialId?: number[];\n}\n\nconst DEFAULT_DB_NAME = 'dev-wallet-passkey';\nconst DEFAULT_STORE_NAME = 'accounts';\nconst META_KEY = '__passkey_accounts__';\n\n/**\n * Signer adapter backed by WebAuthn passkeys. Each signing operation triggers a\n * browser biometric/PIN prompt. Account metadata is persisted in IndexedDB;\n * private keys are managed by the browser/OS and never enter JavaScript.\n *\n * Browser only — requires `navigator.credentials` and `indexedDB`.\n */\nexport class PasskeySignerAdapter extends BaseSignerAdapter {\n\treadonly id = 'passkey';\n\treadonly name = 'Passkey Signer';\n\treadonly allowAutoSign = false;\n\n\t#store: IDBStore;\n\t#provider: PasskeyProvider | null;\n\n\tconstructor(options?: { dbName?: string; storeName?: string; provider?: PasskeyProvider }) {\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\t// Allow injecting a custom provider (useful for testing)\n\t\tthis.#provider = options?.provider ?? null;\n\t}\n\n\t#getProvider(): PasskeyProvider {\n\t\tif (!this.#provider) {\n\t\t\tthrow new Error('PasskeySignerAdapter not initialized. Call initialize() first.');\n\t\t}\n\t\treturn this.#provider;\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tif (!this.#provider) {\n\t\t\tconst { BrowserPasskeyProvider } = await import('@mysten/sui/keypairs/passkey');\n\t\t\tthis.#provider = new BrowserPasskeyProvider('Dev Wallet Passkey', {\n\t\t\t\trp: { id: globalThis.location?.hostname },\n\t\t\t});\n\t\t}\n\n\t\tconst stored = await this.#store.get<StoredPasskeyMeta[]>(META_KEY);\n\t\tif (!stored) return;\n\n\t\tconst provider = this.#getProvider();\n\t\tthis.setInitialAccounts(\n\t\t\tstored.map((meta) => {\n\t\t\t\tconst publicKeyBytes = new Uint8Array(meta.publicKeyBytes);\n\t\t\t\tconst credentialId = meta.credentialId ? new Uint8Array(meta.credentialId) : undefined;\n\t\t\t\tconst signer = new PasskeyKeypair(publicKeyBytes, provider, credentialId);\n\t\t\t\treturn buildManagedAccount(signer, meta.address, meta.label);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprotected override getDefaultLabel(): string {\n\t\treturn `Passkey Account ${this.getAccounts().length + 1}`;\n\t}\n\n\tasync createAccount(options?: CreateAccountOptions) {\n\t\tconst signer = await PasskeyKeypair.getPasskeyInstance(this.#getProvider());\n\t\tconst address = signer.toSuiAddress();\n\t\tconst label = options?.label ?? this.getDefaultLabel();\n\n\t\tconst managedAccount = buildManagedAccount(signer, address, label);\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\t\tawait this.#saveMeta();\n\t\treturn true;\n\t}\n\n\tasync #saveMeta(): Promise<void> {\n\t\tconst meta: StoredPasskeyMeta[] = this.getAccounts().map((a) => {\n\t\t\tconst credentialId = (a.signer as PasskeyKeypair).getCredentialId?.();\n\t\t\treturn {\n\t\t\t\taddress: a.address,\n\t\t\t\tlabel: a.label,\n\t\t\t\tpublicKeyBytes: [...a.signer.getPublicKey().toRawBytes()],\n\t\t\t\t...(credentialId && { credentialId: [...credentialId] }),\n\t\t\t};\n\t\t});\n\t\tawait this.#store.set(META_KEY, meta);\n\t}\n}\n"],"mappings":";;;;;AAqBA,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,WAAW;;;;;;;;AASjB,IAAa,uBAAb,cAA0C,kBAAkB;CAK3D;CACA;CAEA,YAAY,SAA+E;EAC1F,MAAM;YARO;cACE;uBACS;EAOxB,KAAKA,SAAS,IAAI,SACjB,SAAS,UAAU,iBACnB,SAAS,aAAa,kBACvB;EAEA,KAAKC,YAAY,SAAS,YAAY;CACvC;CAEA,eAAgC;EAC/B,IAAI,CAAC,KAAKA,WACT,MAAM,IAAI,MAAM,gEAAgE;EAEjF,OAAO,KAAKA;CACb;CAEA,MAAM,aAA4B;EACjC,IAAI,CAAC,KAAKA,WAAW;GACpB,MAAM,EAAE,2BAA2B,MAAM,OAAO;GAChD,KAAKA,YAAY,IAAI,uBAAuB,sBAAsB,EACjE,IAAI,EAAE,IAAI,WAAW,UAAU,SAAS,EACzC,CAAC;EACF;EAEA,MAAM,SAAS,MAAM,KAAKD,OAAO,IAAyB,QAAQ;EAClE,IAAI,CAAC,QAAQ;EAEb,MAAM,WAAW,KAAKE,aAAa;EACnC,KAAK,mBACJ,OAAO,KAAK,SAAS;GAIpB,OAAO,oBAAoB,IADR,eAAe,IAFP,WAAW,KAAK,cAET,GAAgB,UAD7B,KAAK,eAAe,IAAI,WAAW,KAAK,YAAY,IAAI,MAElD,GAAQ,KAAK,SAAS,KAAK,KAAK;EAC5D,CAAC,CACF;CACD;CAEA,kBAA6C;EAC5C,OAAO,mBAAmB,KAAK,YAAY,CAAC,CAAC,SAAS;CACvD;CAEA,MAAM,cAAc,SAAgC;EACnD,MAAM,SAAS,MAAM,eAAe,mBAAmB,KAAKA,aAAa,CAAC;EAI1E,MAAM,iBAAiB,oBAAoB,QAH3B,OAAO,aAG4B,GAFrC,SAAS,SAAS,KAAK,gBAAgB,CAEY;EACjE,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;EAClD,MAAM,KAAKA,UAAU;EACrB,OAAO;CACR;CAEA,MAAMA,YAA2B;EAChC,MAAM,OAA4B,KAAK,YAAY,CAAC,CAAC,KAAK,MAAM;GAC/D,MAAM,eAAgB,EAAE,OAA0B,kBAAkB;GACpE,OAAO;IACN,SAAS,EAAE;IACX,OAAO,EAAE;IACT,gBAAgB,CAAC,GAAG,EAAE,OAAO,aAAa,CAAC,CAAC,WAAW,CAAC;IACxD,GAAI,gBAAgB,EAAE,cAAc,CAAC,GAAG,YAAY,EAAE;GACvD;EACD,CAAC;EACD,MAAM,KAAKH,OAAO,IAAI,UAAU,IAAI;CACrC;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-cli-adapter.d.mts","names":[],"sources":["../../src/adapters/remote-cli-adapter.ts"],"mappings":";;;;;;AAqEA;;;;;;cAAa,cAAA,SAAuB,MAAA;EAAA;cAOvB,OAAA;IACX,OAAA;IACA,SAAA,EAAW,SAAA;IACX,MAAA,EAAQ,eAAA;IACR,YAAA;IACA,SAAA;EAAA;EAUK,IAAA,CAAK,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,UAAA,CAAW,WAAA;EAOnD,YAAA,
|
|
1
|
+
{"version":3,"file":"remote-cli-adapter.d.mts","names":[],"sources":["../../src/adapters/remote-cli-adapter.ts"],"mappings":";;;;;;AAqEA;;;;;;cAAa,cAAA,SAAuB,MAAA;EAAA;cAOvB,OAAA;IACX,OAAA;IACA,SAAA,EAAW,SAAA;IACX,MAAA,EAAQ,eAAA;IACR,YAAA;IACA,SAAA;EAAA;EAUK,IAAA,CAAK,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,UAAA,CAAW,WAAA;EAOnD,YAAA,IAAgB,eAAA;EAIhB,YAAA,IAAgB,SAAA;EAIP,YAAA;EAIM,eAAA,CAAgB,KAAA,EAAO,UAAA,GAAU,OAAA;;;;EA8BjC,mBAAA,CAAoB,MAAA,EAAQ,UAAA,GAAa,OAAA;AAAA;;;;;;;;cAgB5C,gBAAA,SAAyB,iBAAA;EAAA;WAC5B,EAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;EAAA,UAEU,eAAA;EAAA,OAOZ,UAAA,CAAW,MAAA;EAAA,WAKP,WAAA;EAAA,WAIA,SAAA;cASC,OAAA;IAAY,YAAA;IAAuB,KAAA;EAAA;EAAA,IAgB3C,QAAA;EAIE,UAAA,IAAc,OAAA;EAyBd,qBAAA,IAAyB,OAAA,CAC9B,KAAA;IAAQ,OAAA;IAAiB,MAAA;IAAgB,KAAA;EAAA;EAgBpC,aAAA,CAAc,OAAA,EAAS,oBAAA,GAAuB,OAAA,CAAQ,cAAA;EA2BtD,aAAA,CAAc,OAAA,WAAkB,OAAA;EAQ7B,OAAA;AAAA"}
|