|
| 1 | +--- |
| 2 | +name: spin-up-local-devstack |
| 3 | +description: Use when the user wants a FULLY-LOCAL stack (no testnet dependency) for Sui Stack Messaging — including a LOCAL Seal key server so message decryption works on localnet. Uses @mysten-incubation/devstack to compose a local Sui node + local-keygen Seal + (optional) local Walrus + published Move packages + the chat-app from one config file. The localnet counterpart to spin-up-e2e-stack (which is testnet-first and cannot decrypt on localnet). Requires Docker + Node >= 24. Trigger phrases - "fully local stack", "localnet with working Seal", "local seal key server", "devstack", "no testnet dependency", "local encryption", "decrypt on localnet", "all-local messaging stack". |
| 4 | +--- |
| 5 | + |
| 6 | +# Spin up a fully-local stack with devstack (incl. local Seal) |
| 7 | + |
| 8 | +A one-command, all-local Sui Stack Messaging stack via `@mysten-incubation/devstack`: local Sui node + |
| 9 | +a **local Seal key server** + the messaging Move package + a browser dev-wallet + the chat-app. The |
| 10 | +payoff is that message **decryption works fully locally** — the testnet-first |
| 11 | +[`spin-up-e2e-stack`](../spin-up-e2e-stack/SKILL.md) can't decrypt on localnet (Seal has no localnet; |
| 12 | +the canonical key servers can't authorize localnet group objects). |
| 13 | + |
| 14 | +This was validated end-to-end (`create → send → DECRYPT`). The chat-app-side integration is documented |
| 15 | +in [`chat-app/docs/DEVSTACK.md`](../../../chat-app/docs/DEVSTACK.md); the friction log + upstream doc |
| 16 | +links are in [`reference/NOTES.md`](./reference/NOTES.md). |
| 17 | + |
| 18 | +## Requirements |
| 19 | + |
| 20 | +- **Docker, running.** sui / seal run as containers; first boot pulls images (slow). |
| 21 | +- **Node >= 24** (devstack `engines`). With nvm: `nvm install 24 && nvm use 24`. |
| 22 | +- **pnpm 10.x for installs.** On pnpm v11 a fresh install trips the esbuild build gate and the |
| 23 | + `minimumReleaseAge` floor on devstack's fresh transitive deps. Use `npx pnpm@10 install`. See |
| 24 | + [`docs/pnpm-v11-troubleshooting.md`](../../../docs/pnpm-v11-troubleshooting.md). |
| 25 | +- **No native localnet on `:9000`.** Stop any `sui start` first. |
| 26 | +- The incubation deps stay **chat-app devDependencies only** (never the canonical SDK). |
| 27 | + |
| 28 | +## Run |
| 29 | + |
| 30 | +```bash |
| 31 | +cd chat-app |
| 32 | +npx pnpm@10 install # devDeps: @mysten-incubation/devstack@0.1.1, @mysten-incubation/dev-wallet@0.3.0, @mysten/signers@1.0.5 |
| 33 | +pnpm devstack up # sui + local Seal + publish + codegen + serve (add --renderer plain for clean logs) |
| 34 | +# offline sanity check (no Docker): pnpm devstack config |
| 35 | +``` |
| 36 | + |
| 37 | +Open the printed `http://dev.chat-app-local.chat-app.localhost:5175`, connect the **Dev Wallet** |
| 38 | +(funded `publisher`/`alice`/`bob`), create a group, send, refresh → it decrypts. Send/decrypt also need |
| 39 | +the relayer (below). |
| 40 | + |
| 41 | +## How it fits together |
| 42 | + |
| 43 | +`devstack up` brings up: Sui node → publisher account → messaging package publish → local-keygen Seal → |
| 44 | +dev-wallet server → chat-app (Vite), writing typed config to `chat-app/src/generated/` (gitignored). |
| 45 | +The chat-app consumes it through `vite.config.ts` (`devstackVitePlugin()` aliases `@generated`; a |
| 46 | +`virtual:devstack-app-config` shim keeps it dev-only) and `src/lib/devstack-config.ts`. Full walkthrough: |
| 47 | +[`chat-app/docs/DEVSTACK.md`](../../../chat-app/docs/DEVSTACK.md). |
| 48 | + |
| 49 | +The load-bearing, non-obvious bits (all handled in `chat-app/devstack.config.ts` + `devstack-config.ts`): |
| 50 | + |
| 51 | +- **Publishing the package.** devstack does one `Transaction.publish({ modules })`, which *merges* |
| 52 | + bundled unpublished deps into one package. `sui_groups` ships a committed `Published.toml`, so the |
| 53 | + `-e testnet` build links its testnet id (absent on localnet) instead of bundling. Fix: materialize a |
| 54 | + gitignored copy of `sui_groups` with `Published.toml`/`Move.lock` stripped + a local Move dep, patch |
| 55 | + `suins` MVR→git, strip messaging's `Published.toml`. Net: messaging + sui_groups merge into one local |
| 56 | + package id (so `messaging` and `permissionedGroups` configs share it). The app recovers the |
| 57 | + namespace/version singletons + the groups id from the publish tx via GraphQL at bootstrap. |
| 58 | +- **Seal: one server, `sealThreshold: 1`.** Two local-keygen servers collide in codegen in 0.1.1. |
| 59 | +- **Dev-wallet: register it yourself.** `devstackVitePlugin()` only aliases `@generated` — it does NOT |
| 60 | + inject a wallet. devstack runs the wallet *server* (funded accounts); the app builds a |
| 61 | + `DevstackSignerAdapter` from `@generated/dapp-kit/config`, `register()`s a `DevWallet`, and |
| 62 | + `mountDevWallet()`s the panel. Serialize sign calls (the DevWallet allows one pending sign). |
| 63 | + |
| 64 | +## Relayer |
| 65 | + |
| 66 | +devstack does not run the reference relayer; send/fetch go through it. Run it separately |
| 67 | +([`spin-up-relayer`](../spin-up-relayer/SKILL.md)) on the host, pointed at the **direct host-published |
| 68 | +validator port** (not the Traefik-routed `:9000`, which 400s on gRPC): |
| 69 | + |
| 70 | +```bash |
| 71 | +docker port <devstack-…-sui-validator> 9000 # e.g. 127.0.0.1:51000 |
| 72 | +# relayer/.env: SUI_RPC_URL=http://127.0.0.1:51000 ; GROUPS_PACKAGE_ID=<merged id from src/generated/packages.ts> |
| 73 | +cd relayer && cargo run # :3000 ; the chat-app reads VITE_RELAYER_URL (default localhost:3000) |
| 74 | +``` |
| 75 | + |
| 76 | +## Walrus (optional) |
| 77 | + |
| 78 | +Walrus is **off the critical path for the create → send → decrypt loop**: decryption never touches |
| 79 | +it (delivery = relayer store + on-chain refs; Walrus is recovery / attachments only), so leaving it |
| 80 | +out doesn't compromise local decryption. Only message **attachments** need it. |
| 81 | + |
| 82 | +The seam that stays non-local is **archival** — the reference relayer archives to its default |
| 83 | +**testnet** Walrus. Making *that* local is a tracked follow-up (not done here): devstack offers |
| 84 | +`walrus({ local: { nodeCount, shards } })` + `walCoin`, but the relayer + chat-app talk **HTTP** to a |
| 85 | +publisher/aggregator gateway (not the Walrus SDK) — whether devstack's local Walrus exposes those is |
| 86 | +the open question — and it also needs repointing the relayer's `WALRUS_PUBLISHER_URL`/`AGGREGATOR_URL`, |
| 87 | +enabling attachments (off in devstack mode), and wiring the indexer + SDK `RecoveryTransport`. To |
| 88 | +experiment now, add `walrus({ local })` + `walCoin` to `devstack.config.ts` and wire `VITE_WALRUS_*`. |
| 89 | + |
| 90 | +## Gotchas (full list in `reference/NOTES.md`) |
| 91 | + |
| 92 | +- **First boot is slow** (image pulls). `.devstack/` + `src/generated/` are gitignored (regenerated each `up`). |
| 93 | +- **Reset:** `devstack wipe --yes`; hard Docker reset `docker rm -f $(docker ps -aq --filter name=devstack)` |
| 94 | + (`devstack prune` only removes idle groups). Re-emit codegen: `devstack apply`. |
| 95 | +- **"A signing request is already pending"** = concurrent signs vs the DevWallet's one-pending model → serialize app-side. |
| 96 | +- **Connect hangs at "Confirm connection in the wallet"** = no `mountDevWallet()`. |
| 97 | +- **Relayer "grpc-status header missing, HTTP 400"** = gRPC through Traefik → use the host-published port. |
| 98 | + |
| 99 | +## Cross-links |
| 100 | + |
| 101 | +- Testnet-first / manual localnet path: [`spin-up-e2e-stack`](../spin-up-e2e-stack/SKILL.md). |
| 102 | +- Run the relayer: [`spin-up-relayer`](../spin-up-relayer/SKILL.md). |
| 103 | +- Why Seal can't work on a localnet + testnet-Seal hybrid: [`debug-encryption-flow`](../debug-encryption-flow/SKILL.md) (Stage 3). |
| 104 | +- devstack docs: <https://github.com/MystenLabs/ts-sdks-incubation/tree/main/packages/docs/content/devstack> |
| 105 | + · dev-wallet docs: <https://github.com/MystenLabs/ts-sdks-incubation/tree/main/packages/docs/content/dev-wallet> |
0 commit comments