@toon-protocol/townhouse 0.1.0-rc5 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -0
- package/dist/chunk-5O4SBV5O.js +538 -0
- package/dist/chunk-5O4SBV5O.js.map +1 -0
- package/dist/chunk-GQNBZJ6F.js +39 -0
- package/dist/chunk-GQNBZJ6F.js.map +1 -0
- package/dist/{chunk-UTFWPLTB.js → chunk-I2R4CRUX.js} +2 -22
- package/dist/chunk-I2R4CRUX.js.map +1 -0
- package/dist/chunk-JCOFMUPL.js +65 -0
- package/dist/chunk-JCOFMUPL.js.map +1 -0
- package/dist/chunk-W33MEOPM.js +22111 -0
- package/dist/chunk-W33MEOPM.js.map +1 -0
- package/dist/cli.d.ts +94 -2
- package/dist/cli.js +3116 -111
- package/dist/cli.js.map +1 -1
- package/dist/compose/townhouse-dev.yml +1 -1
- package/dist/compose/townhouse-hs.yml +126 -19
- package/dist/{demo-MJR47QHZ.js → demo-3DWRDMYY.js} +3 -2
- package/dist/{demo-MJR47QHZ.js.map → demo-3DWRDMYY.js.map} +1 -1
- package/dist/image-manifest.json +12 -12
- package/dist/index.d.ts +1286 -655
- package/dist/index.js +37 -140
- package/dist/index.js.map +1 -1
- package/dist/manager-SsneW_Mj.d.ts +519 -0
- package/dist/rsa-from-seed-XIT6EU73.js +67 -0
- package/dist/rsa-from-seed-XIT6EU73.js.map +1 -0
- package/dist/tui-OIFXGBTL.js +625 -0
- package/dist/tui-OIFXGBTL.js.map +1 -0
- package/package.json +19 -3
- package/dist/chunk-IB6TNCUQ.js +0 -8274
- package/dist/chunk-IB6TNCUQ.js.map +0 -1
- package/dist/chunk-UTFWPLTB.js.map +0 -1
|
@@ -48,7 +48,7 @@ services:
|
|
|
48
48
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
49
49
|
townhouse-dev-connector:
|
|
50
50
|
# Image tag must match DEFAULT_CONNECTOR_IMAGE in packages/townhouse/src/constants.ts
|
|
51
|
-
image: ghcr.io/toon-protocol/connector:3.
|
|
51
|
+
image: ghcr.io/toon-protocol/connector:3.8.0
|
|
52
52
|
container_name: townhouse-dev-connector
|
|
53
53
|
networks:
|
|
54
54
|
- townhouse-dev-net
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
# Story 45.4 boots only connector + townhouse-api at apex install
|
|
23
23
|
#
|
|
24
24
|
# Digest placeholders (substituted at build time from dist/image-manifest.json):
|
|
25
|
-
# @sha256:
|
|
26
|
-
# @sha256:
|
|
27
|
-
# @sha256:
|
|
28
|
-
# @sha256:
|
|
29
|
-
# @sha256:
|
|
25
|
+
# @sha256:43f592ae933cdd2a2626b25b4f866caec3c1af188fa379c0cae0a83b9bd43cf3 → @sha256:<hex>
|
|
26
|
+
# @sha256:e6919812ebe408f1b4ed714916f0f0db86ca4f06563eb01b64370a47dc6a6d50 → @sha256:<hex>
|
|
27
|
+
# @sha256:5ca03ec95205b3c24f44a87ed256c599ef1811a9cc55e380fd81a557974c3871 → @sha256:<hex>
|
|
28
|
+
# @sha256:74db846c9c5b1595d4b7d09edbf42dcb60bcbfd1831b6d591cd7100c188597c5 → @sha256:<hex>
|
|
29
|
+
# @sha256:3343c19649290043e521c81b467b7c6410b8eaedd76d48804ea9b6fc810cddb0 → @sha256:<hex>
|
|
30
30
|
#
|
|
31
31
|
# Scope guard (Story 45.2 does NOT include):
|
|
32
32
|
# - ator-sidecar / ator-sidecar-relay (connector v3.5.x does HS publishing in-process)
|
|
@@ -50,15 +50,29 @@
|
|
|
50
50
|
|
|
51
51
|
networks:
|
|
52
52
|
townhouse-hs-net:
|
|
53
|
+
name: townhouse-hs-net
|
|
53
54
|
driver: bridge
|
|
54
55
|
|
|
55
56
|
volumes:
|
|
56
57
|
# Named volume for the connector's .anyone keypair + HS state.
|
|
57
58
|
# Survives `docker compose down`; delete to rotate the .anyone address.
|
|
59
|
+
#
|
|
60
|
+
# The explicit `name:` fields bypass Compose's project-prefix mechanism.
|
|
61
|
+
# Without them, Compose derives the project name from the compose file's
|
|
62
|
+
# parent directory (e.g. `compose` when the file lives at
|
|
63
|
+
# ~/.townhouse/compose/townhouse-hs.yml or <tmpDir>/compose/townhouse-hs.yml),
|
|
64
|
+
# producing on-disk volumes named `compose_townhouse-hs-anon` etc. — which
|
|
65
|
+
# would break the test 5 `volumeExists('townhouse-hs-anon')` assertion AND
|
|
66
|
+
# operator-facing rotate-keys docs that reference the bare name. Discovered
|
|
67
|
+
# by Story 46.4 live gate run (Finding H, 2026-05-11).
|
|
58
68
|
townhouse-hs-anon:
|
|
69
|
+
name: townhouse-hs-anon
|
|
59
70
|
townhouse-hs-town-data:
|
|
71
|
+
name: townhouse-hs-town-data
|
|
60
72
|
townhouse-hs-mill-data:
|
|
73
|
+
name: townhouse-hs-mill-data
|
|
61
74
|
townhouse-hs-dvm-data:
|
|
75
|
+
name: townhouse-hs-dvm-data
|
|
62
76
|
|
|
63
77
|
services:
|
|
64
78
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -70,10 +84,32 @@ services:
|
|
|
70
84
|
#
|
|
71
85
|
# NFR7: connector MUST NOT mount /var/run/docker.sock.
|
|
72
86
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
87
|
+
# One-shot init: ensure the .anyone key volume is owned by uid 1000 (node)
|
|
88
|
+
# before the connector starts. Docker creates named volumes as root on first
|
|
89
|
+
# boot; the connector (running as node) cannot write the HS keypair/hostname
|
|
90
|
+
# without this chown step.
|
|
91
|
+
connector-init:
|
|
92
|
+
image: busybox:1.37@sha256:9532d8c39891ca2ecde4d30d7710e01fb739c87a8b9299685c63704296b16028
|
|
93
|
+
user: root
|
|
94
|
+
# anon (Tor-based) requires the HS dir to be mode 0700 — too-permissive
|
|
95
|
+
# directories cause an immediate abort. Docker creates volumes as root 755.
|
|
96
|
+
command: ['sh', '-c', 'mkdir -p /data && chown -R 1000:1000 /data && chmod 700 /data']
|
|
97
|
+
volumes:
|
|
98
|
+
- townhouse-hs-anon:/data
|
|
99
|
+
restart: 'no'
|
|
100
|
+
networks:
|
|
101
|
+
- townhouse-hs-net
|
|
102
|
+
|
|
73
103
|
connector:
|
|
74
|
-
image: ghcr.io/toon-protocol/connector@sha256:
|
|
104
|
+
image: ghcr.io/toon-protocol/connector@sha256:3343c19649290043e521c81b467b7c6410b8eaedd76d48804ea9b6fc810cddb0
|
|
105
|
+
# v3.5.1 has the multi-arch manifest but the default resolves to arm64 on
|
|
106
|
+
# some Docker versions. Pin to amd64 explicitly until the manifest is fixed.
|
|
107
|
+
platform: linux/amd64
|
|
75
108
|
container_name: townhouse-hs-connector
|
|
76
109
|
hostname: connector
|
|
110
|
+
depends_on:
|
|
111
|
+
connector-init:
|
|
112
|
+
condition: service_completed_successfully
|
|
77
113
|
networks:
|
|
78
114
|
- townhouse-hs-net
|
|
79
115
|
ports:
|
|
@@ -81,7 +117,11 @@ services:
|
|
|
81
117
|
- '127.0.0.1:9401:9401'
|
|
82
118
|
volumes:
|
|
83
119
|
# Rendered connector config (Story 45.4 writes this on first-run).
|
|
84
|
-
|
|
120
|
+
# TOWNHOUSE_HOME is exported by `townhouse hs up` as the operator's
|
|
121
|
+
# config dir (default ~/.townhouse; --config-dir overrides). Docker does
|
|
122
|
+
# NOT expand `~` in bind-mount sources, so the path must come through
|
|
123
|
+
# Compose interpolation.
|
|
124
|
+
- ${TOWNHOUSE_HOME}/connector.yaml:/config/connector.yaml:ro
|
|
85
125
|
# .anyone keypair + HS state (persists across down/up cycles).
|
|
86
126
|
- townhouse-hs-anon:/var/lib/anon/hs
|
|
87
127
|
environment:
|
|
@@ -92,7 +132,11 @@ services:
|
|
|
92
132
|
interval: 10s
|
|
93
133
|
timeout: 5s
|
|
94
134
|
retries: 5
|
|
95
|
-
|
|
135
|
+
# The managed anon daemon needs ~60-120s to bootstrap circuits and publish
|
|
136
|
+
# the HS hostname before the connector starts its admin API. Keep
|
|
137
|
+
# start_period generous so health-check failures during bootstrap don't
|
|
138
|
+
# prematurely mark the container unhealthy.
|
|
139
|
+
start_period: 150s
|
|
96
140
|
restart: unless-stopped
|
|
97
141
|
|
|
98
142
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -108,8 +152,20 @@ services:
|
|
|
108
152
|
# Port D21-008: Fastify host API on 127.0.0.1:28090.
|
|
109
153
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
110
154
|
townhouse-api:
|
|
111
|
-
image: ghcr.io/toon-protocol/townhouse-api@sha256:
|
|
155
|
+
image: ghcr.io/toon-protocol/townhouse-api@sha256:43f592ae933cdd2a2626b25b4f866caec3c1af188fa379c0cae0a83b9bd43cf3
|
|
112
156
|
container_name: townhouse-hs-api
|
|
157
|
+
# Run as the operator's host UID so bind-mounted ~/.townhouse files
|
|
158
|
+
# (rw------- 600) are readable. TOWNHOUSE_UID is injected by `townhouse hs up`.
|
|
159
|
+
# Defaults to 1000 (the standard first-user UID on Linux).
|
|
160
|
+
user: '${TOWNHOUSE_UID:-1000}'
|
|
161
|
+
# Add the host's docker socket group as a supplementary group so the
|
|
162
|
+
# non-root container user can read/write /var/run/docker.sock (typically
|
|
163
|
+
# owned root:docker mode 660 on Linux). Without this, every dockerode call
|
|
164
|
+
# — including the `pull-image` step of POST /api/nodes — fails with
|
|
165
|
+
# `connect EACCES /var/run/docker.sock`. TOWNHOUSE_DOCKER_GID is injected
|
|
166
|
+
# by `townhouse hs up` via `statSync('/var/run/docker.sock').gid`.
|
|
167
|
+
group_add:
|
|
168
|
+
- '${TOWNHOUSE_DOCKER_GID:-0}'
|
|
113
169
|
networks:
|
|
114
170
|
- townhouse-hs-net
|
|
115
171
|
depends_on:
|
|
@@ -122,18 +178,60 @@ services:
|
|
|
122
178
|
# Docker socket — townhouse-api is the sole orchestration surface.
|
|
123
179
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
124
180
|
# Operator home — wallet, config, compose files, snapshots (RW).
|
|
125
|
-
|
|
181
|
+
# TOWNHOUSE_HOME is exported by `townhouse hs up` (see connector volume
|
|
182
|
+
# above). The container-side path stays `/.townhouse` so config.yaml
|
|
183
|
+
# `TOWNHOUSE_CONFIG: /.townhouse/config.yaml` resolves identically
|
|
184
|
+
# regardless of the operator's host-side config dir.
|
|
185
|
+
- ${TOWNHOUSE_HOME}:/.townhouse:rw
|
|
186
|
+
# Wallet dir mirrored at the host-absolute path so config.yaml's
|
|
187
|
+
# `wallet.encrypted_path` (an absolute host path set by `townhouse init`)
|
|
188
|
+
# resolves correctly inside the container. TOWNHOUSE_WALLET_DIR is
|
|
189
|
+
# injected by `townhouse hs up` as path.dirname(config.wallet.encrypted_path).
|
|
190
|
+
- ${TOWNHOUSE_WALLET_DIR:-~/.townhouse}:${TOWNHOUSE_WALLET_DIR:-~/.townhouse}:ro
|
|
126
191
|
environment:
|
|
127
192
|
# Override entrypoint default '/config/config.yaml' so the API reads from
|
|
128
193
|
# the mounted operator-home dir (where Story 45.4 writes config.yaml).
|
|
129
194
|
TOWNHOUSE_CONFIG: /.townhouse/config.yaml
|
|
195
|
+
# Bind on all interfaces inside the container so Docker's port mapping
|
|
196
|
+
# (127.0.0.1:28090:28090) can reach it from the host. ALLOW_REMOTE=1
|
|
197
|
+
# is required when HOST is non-loopback; Docker's host-only binding on
|
|
198
|
+
# the outer port (127.0.0.1) is the actual access control gate.
|
|
199
|
+
TOWNHOUSE_API_HOST: 0.0.0.0
|
|
200
|
+
TOWNHOUSE_API_ALLOW_REMOTE: '1'
|
|
130
201
|
# Wallet decryption password — operator must export TOWNHOUSE_WALLET_PASSWORD
|
|
131
|
-
# in the shell that runs `docker compose up`.
|
|
132
|
-
#
|
|
133
|
-
|
|
202
|
+
# in the shell that runs `docker compose up`. The container-side
|
|
203
|
+
# entrypoint (entrypoint-townhouse-api.ts) enforces the password
|
|
204
|
+
# requirement at startup and exits 1 if it is missing — so the YAML
|
|
205
|
+
# uses `:-` (lenient default) here instead of `:?` (Compose-time
|
|
206
|
+
# mandatory error). The `:?` variant would also force `docker compose
|
|
207
|
+
# down` to error out unless the operator pre-exports the password,
|
|
208
|
+
# which broke the teardown flow. Discovered by Story 46.4 live gate
|
|
209
|
+
# run (Finding J, 2026-05-11).
|
|
210
|
+
TOWNHOUSE_WALLET_PASSWORD: '${TOWNHOUSE_WALLET_PASSWORD:-}'
|
|
211
|
+
# Pass the host-side compose-interpolation values through to the
|
|
212
|
+
# townhouse-api container, because the API itself shells out to
|
|
213
|
+
# `docker compose -f /.townhouse/compose/townhouse-hs.yml up -d <type>`
|
|
214
|
+
# for each lazy peer-node provisioning request (Story 46.2). That
|
|
215
|
+
# nested compose re-parses the SAME YAML and needs the same env vars
|
|
216
|
+
# set — otherwise the townhouse-api volume specs interpolate to
|
|
217
|
+
# `:/.townhouse:rw` (empty source) and the inner `up` aborts with
|
|
218
|
+
# `invalid spec: :/.townhouse:rw: empty section between colons`.
|
|
219
|
+
# All four values are HOST paths/IDs (because Docker bind-mount
|
|
220
|
+
# sources are resolved by the daemon, which sees host paths).
|
|
221
|
+
# Discovered by Story 46.4 live gate run (Finding L, 2026-05-12).
|
|
222
|
+
TOWNHOUSE_HOME: '${TOWNHOUSE_HOME}'
|
|
223
|
+
TOWNHOUSE_WALLET_DIR: '${TOWNHOUSE_WALLET_DIR}'
|
|
224
|
+
TOWNHOUSE_UID: '${TOWNHOUSE_UID:-1000}'
|
|
225
|
+
TOWNHOUSE_DOCKER_GID: '${TOWNHOUSE_DOCKER_GID:-0}'
|
|
226
|
+
# MILL_RELAYS is read by POST /api/nodes {type:'mill'} preflight check
|
|
227
|
+
# inside the townhouse-api process. It must be in the API container's env
|
|
228
|
+
# (not only the mill container's env) so the check works correctly.
|
|
229
|
+
MILL_RELAYS: '${MILL_RELAYS:-}'
|
|
134
230
|
healthcheck:
|
|
135
231
|
# nosemgrep: trailofbits.generic.wget-unencrypted-url.wget-unencrypted-url -- container-internal probe
|
|
136
|
-
|
|
232
|
+
# Use 127.0.0.1 (not localhost) to avoid IPv6 resolution surprises. The
|
|
233
|
+
# townhouse-api exposes /api/transport (not /api/health).
|
|
234
|
+
test: ['CMD', 'wget', '-q', '--spider', 'http://127.0.0.1:28090/api/transport']
|
|
137
235
|
interval: 10s
|
|
138
236
|
timeout: 5s
|
|
139
237
|
retries: 5
|
|
@@ -154,7 +252,7 @@ services:
|
|
|
154
252
|
# start at first run).
|
|
155
253
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
156
254
|
town:
|
|
157
|
-
image: ghcr.io/toon-protocol/town@sha256:
|
|
255
|
+
image: ghcr.io/toon-protocol/town@sha256:e6919812ebe408f1b4ed714916f0f0db86ca4f06563eb01b64370a47dc6a6d50
|
|
158
256
|
container_name: townhouse-hs-town
|
|
159
257
|
profiles: [town]
|
|
160
258
|
networks:
|
|
@@ -179,7 +277,15 @@ services:
|
|
|
179
277
|
NODE_EVM_ADDRESS: ''
|
|
180
278
|
# Derived from HD wallet at runtime (Story 45.4 / Epic 46).
|
|
181
279
|
NODE_NOSTR_SECRET_KEY: '${TOWN_SECRET_KEY:-}'
|
|
182
|
-
|
|
280
|
+
# Town reads TOON_SETTLEMENT_PRIVATE_KEY (packages/town/src/cli.ts:305),
|
|
281
|
+
# 0x-prefixed 32-byte hex. The API passes the already-0x-prefixed value
|
|
282
|
+
# via TOWN_SETTLEMENT_PRIVATE_KEY. Previously this was wired to the wrong
|
|
283
|
+
# env var name (`SETTLEMENT_PRIVATE_KEY`), so town crash-looped at boot
|
|
284
|
+
# with `TOON_SETTLEMENT_PRIVATE_KEY must be a 0x-prefixed 32-byte hex
|
|
285
|
+
# string` and never reached its /health endpoint — failing the gate
|
|
286
|
+
# at step 5 (healthcheck). Story 46.4 live gate run (Finding N+O,
|
|
287
|
+
# 2026-05-12).
|
|
288
|
+
TOON_SETTLEMENT_PRIVATE_KEY: '${TOWN_SETTLEMENT_PRIVATE_KEY:-}'
|
|
183
289
|
PARENT_EVM_ADDRESS: '${APEX_EVM_ADDRESS:-}'
|
|
184
290
|
TOON_CONNECTOR_LOG_LEVEL: '${TOON_CONNECTOR_LOG_LEVEL:-warn}'
|
|
185
291
|
volumes:
|
|
@@ -197,7 +303,7 @@ services:
|
|
|
197
303
|
# Lazy-provisioned via Epic 46: `townhouse node add mill`
|
|
198
304
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
199
305
|
mill:
|
|
200
|
-
image: ghcr.io/toon-protocol/mill@sha256:
|
|
306
|
+
image: ghcr.io/toon-protocol/mill@sha256:5ca03ec95205b3c24f44a87ed256c599ef1811a9cc55e380fd81a557974c3871
|
|
201
307
|
container_name: townhouse-hs-mill
|
|
202
308
|
profiles: [mill]
|
|
203
309
|
networks:
|
|
@@ -229,7 +335,8 @@ services:
|
|
|
229
335
|
TOON_CONNECTOR_LOG_LEVEL: '${TOON_CONNECTOR_LOG_LEVEL:-warn}'
|
|
230
336
|
volumes:
|
|
231
337
|
# Operator-managed mill config (Epic 46 provisions this on `townhouse node add mill`).
|
|
232
|
-
|
|
338
|
+
# TOWNHOUSE_HOME is exported by `townhouse hs up` (see connector volume above).
|
|
339
|
+
- ${TOWNHOUSE_HOME}/mill.config.json:/config/mill.config.json:ro
|
|
233
340
|
- townhouse-hs-mill-data:/data
|
|
234
341
|
healthcheck:
|
|
235
342
|
test: ['CMD', 'wget', '-q', '--spider', 'http://localhost:3200/health']
|
|
@@ -244,7 +351,7 @@ services:
|
|
|
244
351
|
# Lazy-provisioned via Epic 46: `townhouse node add dvm`
|
|
245
352
|
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
246
353
|
dvm:
|
|
247
|
-
image: ghcr.io/toon-protocol/dvm@sha256:
|
|
354
|
+
image: ghcr.io/toon-protocol/dvm@sha256:74db846c9c5b1595d4b7d09edbf42dcb60bcbfd1831b6d591cd7100c188597c5
|
|
248
355
|
container_name: townhouse-hs-dvm
|
|
249
356
|
profiles: [dvm]
|
|
250
357
|
networks:
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_CONNECTOR_IMAGE
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GQNBZJ6F.js";
|
|
5
|
+
import "./chunk-I2R4CRUX.js";
|
|
5
6
|
|
|
6
7
|
// src/presets/demo.ts
|
|
7
8
|
import { join } from "path";
|
|
@@ -114,4 +115,4 @@ export {
|
|
|
114
115
|
defaultLeasesPath,
|
|
115
116
|
resolveChainEndpoints
|
|
116
117
|
};
|
|
117
|
-
//# sourceMappingURL=demo-
|
|
118
|
+
//# sourceMappingURL=demo-3DWRDMYY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/presets/demo.ts"],"sourcesContent":["/**\n * `--preset=demo` configuration (Story D2).\n *\n * Non-interactive preset for the TOON demo: 1 town, 1 mill (EVM<->SOL pair),\n * 1 dvm, ATOR transport ON, all fees zeroed (demo = free). Chain RPC URLs are\n * sourced from `deploy/akash/leases.json` if present, otherwise from local\n * devnet defaults documented in CLAUDE.md (Anvil 28545, Solana 28899).\n *\n * Future presets (test, prod) follow the same shape — see {@link PresetBuilder}.\n *\n * NOTE on schema reach: this preset writes mill chain endpoints into a\n * `chains` field on the mill node config. The orchestrator wiring that\n * forwards these into MILL_CONFIG_JSON is out of scope for D2 — for now the\n * field round-trips through the YAML so future stories (and the dashboard)\n * can read it without re-deriving it from leases.json.\n */\n\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport type { TownhouseConfig } from '../config/schema.js';\nimport { DEFAULT_CONNECTOR_IMAGE } from '../constants.js';\n\n/**\n * Preset identifier — keep the union closed so we surface unknown presets at\n * the CLI boundary instead of silently falling through to defaults.\n */\nexport type PresetName = 'demo';\n\n/**\n * Local-devnet fallback URLs (CLAUDE.md \"Townhouse Dev Stack\" 28xxx range).\n * Used when `deploy/akash/leases.json` is absent or unreadable.\n */\nexport const LOCAL_DEVNET_FALLBACK = {\n anvilUrl: 'http://localhost:28545',\n solanaUrl: 'http://localhost:28899',\n} as const;\n\n/**\n * Deterministic-but-clearly-unsafe password used for the demo wallet when the\n * caller passes `--preset=demo --yes` without `--password`. The string\n * embeds the warning so it shows up in any log scrape; production callers\n * MUST supply their own `--password` (AC-D2-6).\n */\nexport const DEMO_DETERMINISTIC_PASSWORD =\n 'townhouse-demo-INSECURE-do-not-use-in-prod';\n\n/**\n * Shape of `deploy/akash/leases.json` that this preset cares about. The full\n * file emitted by `scripts/akash-deploy.sh` has more fields; we only need\n * RPC + WS URLs here, so the type is intentionally narrow + tolerant.\n */\nexport interface AkashLeases {\n anvil?: {\n url?: string;\n host?: string;\n port?: number | string;\n ws_url?: string;\n };\n solana?: {\n url?: string;\n host?: string;\n port?: number | string;\n ws_host?: string;\n ws_port?: number | string;\n ws_url?: string;\n };\n}\n\nexport interface ResolvedChainEndpoints {\n /** Source of truth for traceability — either an absolute leases.json path or 'local-fallback'. */\n source: string;\n evm: { rpcUrl: string; wsUrl?: string };\n solana: { rpcUrl: string; wsUrl?: string };\n}\n\n/**\n * Read `deploy/akash/leases.json` and extract chain endpoints, falling back\n * to local devnet URLs if the file is missing or any field is unusable.\n *\n * The fallback is per-chain: a leases.json that defines anvil but not solana\n * still gets the local Solana URL (and vice-versa). This keeps half-deployed\n * states usable.\n */\nexport function resolveChainEndpoints(\n leasesPath?: string\n): ResolvedChainEndpoints {\n const localEvm = { rpcUrl: LOCAL_DEVNET_FALLBACK.anvilUrl };\n const localSol = { rpcUrl: LOCAL_DEVNET_FALLBACK.solanaUrl };\n\n if (!leasesPath || !existsSync(leasesPath)) {\n return { source: 'local-fallback', evm: localEvm, solana: localSol };\n }\n\n let parsed: AkashLeases;\n try {\n parsed = JSON.parse(readFileSync(leasesPath, 'utf-8')) as AkashLeases;\n } catch {\n // Malformed JSON — better to demo on local devnets than to error out at\n // wizard-bypass time. Caller never blocks on bad leases data.\n return { source: 'local-fallback', evm: localEvm, solana: localSol };\n }\n\n const evmUrl =\n typeof parsed.anvil?.url === 'string' ? parsed.anvil.url : undefined;\n const evmWs =\n typeof parsed.anvil?.ws_url === 'string' ? parsed.anvil.ws_url : undefined;\n const solUrl =\n typeof parsed.solana?.url === 'string' ? parsed.solana.url : undefined;\n const solWs =\n typeof parsed.solana?.ws_url === 'string'\n ? parsed.solana.ws_url\n : undefined;\n\n return {\n source: leasesPath,\n evm: evmUrl\n ? { rpcUrl: evmUrl, ...(evmWs ? { wsUrl: evmWs } : {}) }\n : localEvm,\n solana: solUrl\n ? { rpcUrl: solUrl, ...(solWs ? { wsUrl: solWs } : {}) }\n : localSol,\n };\n}\n\nexport interface BuildDemoConfigOptions {\n /** Absolute path to the wallet file (typically `<configDir>/wallet.enc`). */\n walletPath: string;\n /**\n * Absolute path to `deploy/akash/leases.json`. Defaults to\n * `<repoRoot>/deploy/akash/leases.json` if not provided. Pass `null` to\n * force local-devnet fallback (used in tests and when the file is known\n * to not exist on the operator's machine).\n */\n leasesPath?: string | null;\n}\n\n/**\n * Default location of the Akash leases file. Resolved relative to CWD —\n * the demo CLI is run from anywhere, but the leases.json that matters lives\n * at `<repo>/deploy/akash/leases.json`.\n */\nexport function defaultLeasesPath(): string {\n return resolve(process.cwd(), 'deploy', 'akash', 'leases.json');\n}\n\n/**\n * Build the full TownhouseConfig for `--preset=demo`.\n *\n * AC-D2-5 invariants enforced here:\n * - 1 town, 1 mill, 1 dvm (all enabled)\n * - feePerEvent = 0, feeBasisPoints = 0, feePerJob = 0\n * - transport.mode = 'ator'\n * - mill.chains contains exactly one EVM<->SOL pair\n */\nexport function buildDemoConfig(\n options: BuildDemoConfigOptions\n): TownhouseConfig {\n const leasesPath =\n options.leasesPath === null\n ? undefined\n : (options.leasesPath ?? defaultLeasesPath());\n\n const endpoints = resolveChainEndpoints(leasesPath);\n\n return {\n nodes: {\n town: {\n enabled: true,\n feePerEvent: 0,\n },\n mill: {\n enabled: true,\n feeBasisPoints: 0,\n // Demo pair: EVM (Anvil) <-> Solana. The orchestrator does not\n // currently consume mill.chains directly — it round-trips through\n // YAML so the dashboard / future stories can read it.\n chains: {\n evm: {\n rpcUrl: endpoints.evm.rpcUrl,\n ...(endpoints.evm.wsUrl ? { wsUrl: endpoints.evm.wsUrl } : {}),\n },\n solana: {\n rpcUrl: endpoints.solana.rpcUrl,\n ...(endpoints.solana.wsUrl\n ? { wsUrl: endpoints.solana.wsUrl }\n : {}),\n },\n },\n pairs: ['EVM<->SOL'],\n },\n dvm: {\n enabled: true,\n feePerJob: 0,\n // Arweave DVM (kind:5094) — frictionless demo pricing. Operators\n // running for real should raise this; entrypoint-dvm.ts treats the\n // value as msats per byte uploaded to Arweave.\n kindPricing: { '5094': 0 },\n },\n },\n wallet: {\n encrypted_path: options.walletPath,\n },\n connector: {\n image: DEFAULT_CONNECTOR_IMAGE,\n adminPort: 9401,\n },\n transport: {\n // 'direct' for the demo because `townhouse up` doesn't bring up a\n // SOCKS5 sidecar — ATOR mode would require one at `socks5://127.0.0.1:28050`\n // (provided by the dev-infra stack but not the operator CLI). Switch\n // to 'ator' once the sidecar story lands in townhouse `up`.\n mode: 'direct',\n },\n api: {\n port: 9400,\n host: '127.0.0.1',\n },\n logging: {\n level: 'info',\n },\n preset: {\n name: 'demo',\n // Source recorded so operators can see at-a-glance whether their demo\n // is hitting Akash or local devnets.\n chainEndpointSource: endpoints.source,\n },\n };\n}\n\n/**\n * Default config dir used by the demo preset when `--config-dir` is omitted.\n * Mirrors the value in cli.ts; duplicated here so tests can construct the\n * same path without importing from the CLI surface.\n */\nexport function defaultDemoConfigDir(): string {\n return join(homedir(), '.townhouse');\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/presets/demo.ts"],"sourcesContent":["/**\n * `--preset=demo` configuration (Story D2).\n *\n * Non-interactive preset for the TOON demo: 1 town, 1 mill (EVM<->SOL pair),\n * 1 dvm, ATOR transport ON, all fees zeroed (demo = free). Chain RPC URLs are\n * sourced from `deploy/akash/leases.json` if present, otherwise from local\n * devnet defaults documented in CLAUDE.md (Anvil 28545, Solana 28899).\n *\n * Future presets (test, prod) follow the same shape — see {@link PresetBuilder}.\n *\n * NOTE on schema reach: this preset writes mill chain endpoints into a\n * `chains` field on the mill node config. The orchestrator wiring that\n * forwards these into MILL_CONFIG_JSON is out of scope for D2 — for now the\n * field round-trips through the YAML so future stories (and the dashboard)\n * can read it without re-deriving it from leases.json.\n */\n\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport type { TownhouseConfig } from '../config/schema.js';\nimport { DEFAULT_CONNECTOR_IMAGE } from '../constants.js';\n\n/**\n * Preset identifier — keep the union closed so we surface unknown presets at\n * the CLI boundary instead of silently falling through to defaults.\n */\nexport type PresetName = 'demo';\n\n/**\n * Local-devnet fallback URLs (CLAUDE.md \"Townhouse Dev Stack\" 28xxx range).\n * Used when `deploy/akash/leases.json` is absent or unreadable.\n */\nexport const LOCAL_DEVNET_FALLBACK = {\n anvilUrl: 'http://localhost:28545',\n solanaUrl: 'http://localhost:28899',\n} as const;\n\n/**\n * Deterministic-but-clearly-unsafe password used for the demo wallet when the\n * caller passes `--preset=demo --yes` without `--password`. The string\n * embeds the warning so it shows up in any log scrape; production callers\n * MUST supply their own `--password` (AC-D2-6).\n */\nexport const DEMO_DETERMINISTIC_PASSWORD =\n 'townhouse-demo-INSECURE-do-not-use-in-prod';\n\n/**\n * Shape of `deploy/akash/leases.json` that this preset cares about. The full\n * file emitted by `scripts/akash-deploy.sh` has more fields; we only need\n * RPC + WS URLs here, so the type is intentionally narrow + tolerant.\n */\nexport interface AkashLeases {\n anvil?: {\n url?: string;\n host?: string;\n port?: number | string;\n ws_url?: string;\n };\n solana?: {\n url?: string;\n host?: string;\n port?: number | string;\n ws_host?: string;\n ws_port?: number | string;\n ws_url?: string;\n };\n}\n\nexport interface ResolvedChainEndpoints {\n /** Source of truth for traceability — either an absolute leases.json path or 'local-fallback'. */\n source: string;\n evm: { rpcUrl: string; wsUrl?: string };\n solana: { rpcUrl: string; wsUrl?: string };\n}\n\n/**\n * Read `deploy/akash/leases.json` and extract chain endpoints, falling back\n * to local devnet URLs if the file is missing or any field is unusable.\n *\n * The fallback is per-chain: a leases.json that defines anvil but not solana\n * still gets the local Solana URL (and vice-versa). This keeps half-deployed\n * states usable.\n */\nexport function resolveChainEndpoints(\n leasesPath?: string\n): ResolvedChainEndpoints {\n const localEvm = { rpcUrl: LOCAL_DEVNET_FALLBACK.anvilUrl };\n const localSol = { rpcUrl: LOCAL_DEVNET_FALLBACK.solanaUrl };\n\n if (!leasesPath || !existsSync(leasesPath)) {\n return { source: 'local-fallback', evm: localEvm, solana: localSol };\n }\n\n let parsed: AkashLeases;\n try {\n parsed = JSON.parse(readFileSync(leasesPath, 'utf-8')) as AkashLeases;\n } catch {\n // Malformed JSON — better to demo on local devnets than to error out at\n // wizard-bypass time. Caller never blocks on bad leases data.\n return { source: 'local-fallback', evm: localEvm, solana: localSol };\n }\n\n const evmUrl =\n typeof parsed.anvil?.url === 'string' ? parsed.anvil.url : undefined;\n const evmWs =\n typeof parsed.anvil?.ws_url === 'string' ? parsed.anvil.ws_url : undefined;\n const solUrl =\n typeof parsed.solana?.url === 'string' ? parsed.solana.url : undefined;\n const solWs =\n typeof parsed.solana?.ws_url === 'string'\n ? parsed.solana.ws_url\n : undefined;\n\n return {\n source: leasesPath,\n evm: evmUrl\n ? { rpcUrl: evmUrl, ...(evmWs ? { wsUrl: evmWs } : {}) }\n : localEvm,\n solana: solUrl\n ? { rpcUrl: solUrl, ...(solWs ? { wsUrl: solWs } : {}) }\n : localSol,\n };\n}\n\nexport interface BuildDemoConfigOptions {\n /** Absolute path to the wallet file (typically `<configDir>/wallet.enc`). */\n walletPath: string;\n /**\n * Absolute path to `deploy/akash/leases.json`. Defaults to\n * `<repoRoot>/deploy/akash/leases.json` if not provided. Pass `null` to\n * force local-devnet fallback (used in tests and when the file is known\n * to not exist on the operator's machine).\n */\n leasesPath?: string | null;\n}\n\n/**\n * Default location of the Akash leases file. Resolved relative to CWD —\n * the demo CLI is run from anywhere, but the leases.json that matters lives\n * at `<repo>/deploy/akash/leases.json`.\n */\nexport function defaultLeasesPath(): string {\n return resolve(process.cwd(), 'deploy', 'akash', 'leases.json');\n}\n\n/**\n * Build the full TownhouseConfig for `--preset=demo`.\n *\n * AC-D2-5 invariants enforced here:\n * - 1 town, 1 mill, 1 dvm (all enabled)\n * - feePerEvent = 0, feeBasisPoints = 0, feePerJob = 0\n * - transport.mode = 'ator'\n * - mill.chains contains exactly one EVM<->SOL pair\n */\nexport function buildDemoConfig(\n options: BuildDemoConfigOptions\n): TownhouseConfig {\n const leasesPath =\n options.leasesPath === null\n ? undefined\n : (options.leasesPath ?? defaultLeasesPath());\n\n const endpoints = resolveChainEndpoints(leasesPath);\n\n return {\n nodes: {\n town: {\n enabled: true,\n feePerEvent: 0,\n },\n mill: {\n enabled: true,\n feeBasisPoints: 0,\n // Demo pair: EVM (Anvil) <-> Solana. The orchestrator does not\n // currently consume mill.chains directly — it round-trips through\n // YAML so the dashboard / future stories can read it.\n chains: {\n evm: {\n rpcUrl: endpoints.evm.rpcUrl,\n ...(endpoints.evm.wsUrl ? { wsUrl: endpoints.evm.wsUrl } : {}),\n },\n solana: {\n rpcUrl: endpoints.solana.rpcUrl,\n ...(endpoints.solana.wsUrl\n ? { wsUrl: endpoints.solana.wsUrl }\n : {}),\n },\n },\n pairs: ['EVM<->SOL'],\n },\n dvm: {\n enabled: true,\n feePerJob: 0,\n // Arweave DVM (kind:5094) — frictionless demo pricing. Operators\n // running for real should raise this; entrypoint-dvm.ts treats the\n // value as msats per byte uploaded to Arweave.\n kindPricing: { '5094': 0 },\n },\n },\n wallet: {\n encrypted_path: options.walletPath,\n },\n connector: {\n image: DEFAULT_CONNECTOR_IMAGE,\n adminPort: 9401,\n },\n transport: {\n // 'direct' for the demo because `townhouse up` doesn't bring up a\n // SOCKS5 sidecar — ATOR mode would require one at `socks5://127.0.0.1:28050`\n // (provided by the dev-infra stack but not the operator CLI). Switch\n // to 'ator' once the sidecar story lands in townhouse `up`.\n mode: 'direct',\n },\n api: {\n port: 9400,\n host: '127.0.0.1',\n },\n logging: {\n level: 'info',\n },\n preset: {\n name: 'demo',\n // Source recorded so operators can see at-a-glance whether their demo\n // is hitting Akash or local devnets.\n chainEndpointSource: endpoints.source,\n },\n };\n}\n\n/**\n * Default config dir used by the demo preset when `--config-dir` is omitted.\n * Mirrors the value in cli.ts; duplicated here so tests can construct the\n * same path without importing from the CLI surface.\n */\nexport function defaultDemoConfigDir(): string {\n return join(homedir(), '.townhouse');\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,cAAc,kBAAkB;AACzC,SAAS,eAAe;AAejB,IAAM,wBAAwB;AAAA,EACnC,UAAU;AAAA,EACV,WAAW;AACb;AAQO,IAAM,8BACX;AAuCK,SAAS,sBACd,YACwB;AACxB,QAAM,WAAW,EAAE,QAAQ,sBAAsB,SAAS;AAC1D,QAAM,WAAW,EAAE,QAAQ,sBAAsB,UAAU;AAE3D,MAAI,CAAC,cAAc,CAAC,WAAW,UAAU,GAAG;AAC1C,WAAO,EAAE,QAAQ,kBAAkB,KAAK,UAAU,QAAQ,SAAS;AAAA,EACrE;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AAAA,EACvD,QAAQ;AAGN,WAAO,EAAE,QAAQ,kBAAkB,KAAK,UAAU,QAAQ,SAAS;AAAA,EACrE;AAEA,QAAM,SACJ,OAAO,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM,MAAM;AAC7D,QAAM,QACJ,OAAO,OAAO,OAAO,WAAW,WAAW,OAAO,MAAM,SAAS;AACnE,QAAM,SACJ,OAAO,OAAO,QAAQ,QAAQ,WAAW,OAAO,OAAO,MAAM;AAC/D,QAAM,QACJ,OAAO,OAAO,QAAQ,WAAW,WAC7B,OAAO,OAAO,SACd;AAEN,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,KAAK,SACD,EAAE,QAAQ,QAAQ,GAAI,QAAQ,EAAE,OAAO,MAAM,IAAI,CAAC,EAAG,IACrD;AAAA,IACJ,QAAQ,SACJ,EAAE,QAAQ,QAAQ,GAAI,QAAQ,EAAE,OAAO,MAAM,IAAI,CAAC,EAAG,IACrD;AAAA,EACN;AACF;AAmBO,SAAS,oBAA4B;AAC1C,SAAO,QAAQ,QAAQ,IAAI,GAAG,UAAU,SAAS,aAAa;AAChE;AAWO,SAAS,gBACd,SACiB;AACjB,QAAM,aACJ,QAAQ,eAAe,OACnB,SACC,QAAQ,cAAc,kBAAkB;AAE/C,QAAM,YAAY,sBAAsB,UAAU;AAElD,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,gBAAgB;AAAA;AAAA;AAAA;AAAA,QAIhB,QAAQ;AAAA,UACN,KAAK;AAAA,YACH,QAAQ,UAAU,IAAI;AAAA,YACtB,GAAI,UAAU,IAAI,QAAQ,EAAE,OAAO,UAAU,IAAI,MAAM,IAAI,CAAC;AAAA,UAC9D;AAAA,UACA,QAAQ;AAAA,YACN,QAAQ,UAAU,OAAO;AAAA,YACzB,GAAI,UAAU,OAAO,QACjB,EAAE,OAAO,UAAU,OAAO,MAAM,IAChC,CAAC;AAAA,UACP;AAAA,QACF;AAAA,QACA,OAAO,CAAC,WAAW;AAAA,MACrB;AAAA,MACA,KAAK;AAAA,QACH,SAAS;AAAA,QACT,WAAW;AAAA;AAAA;AAAA;AAAA,QAIX,aAAa,EAAE,QAAQ,EAAE;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA,WAAW;AAAA,MACT,OAAO;AAAA,MACP,WAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,MAKT,MAAM;AAAA,IACR;AAAA,IACA,KAAK;AAAA,MACH,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA;AAAA;AAAA,MAGN,qBAAqB,UAAU;AAAA,IACjC;AAAA,EACF;AACF;AAOO,SAAS,uBAA+B;AAC7C,SAAO,KAAK,QAAQ,GAAG,YAAY;AACrC;","names":[]}
|
package/dist/image-manifest.json
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"townhouseVersion": "0.1.
|
|
4
|
-
"builtAt": "2026-
|
|
3
|
+
"townhouseVersion": "0.1.1",
|
|
4
|
+
"builtAt": "2026-06-02T01:56:53.991Z",
|
|
5
5
|
"images": {
|
|
6
6
|
"townhouse-api": {
|
|
7
7
|
"name": "ghcr.io/toon-protocol/townhouse-api",
|
|
8
|
-
"tag": "0.1.
|
|
9
|
-
"digest": "sha256:
|
|
8
|
+
"tag": "0.1.1",
|
|
9
|
+
"digest": "sha256:43f592ae933cdd2a2626b25b4f866caec3c1af188fa379c0cae0a83b9bd43cf3"
|
|
10
10
|
},
|
|
11
11
|
"town": {
|
|
12
12
|
"name": "ghcr.io/toon-protocol/town",
|
|
13
|
-
"tag": "0.1.
|
|
14
|
-
"digest": "sha256:
|
|
13
|
+
"tag": "0.1.1",
|
|
14
|
+
"digest": "sha256:e6919812ebe408f1b4ed714916f0f0db86ca4f06563eb01b64370a47dc6a6d50"
|
|
15
15
|
},
|
|
16
16
|
"mill": {
|
|
17
17
|
"name": "ghcr.io/toon-protocol/mill",
|
|
18
|
-
"tag": "0.1.
|
|
19
|
-
"digest": "sha256:
|
|
18
|
+
"tag": "0.1.1",
|
|
19
|
+
"digest": "sha256:5ca03ec95205b3c24f44a87ed256c599ef1811a9cc55e380fd81a557974c3871"
|
|
20
20
|
},
|
|
21
21
|
"dvm": {
|
|
22
22
|
"name": "ghcr.io/toon-protocol/dvm",
|
|
23
|
-
"tag": "0.1.
|
|
24
|
-
"digest": "sha256:
|
|
23
|
+
"tag": "0.1.1",
|
|
24
|
+
"digest": "sha256:74db846c9c5b1595d4b7d09edbf42dcb60bcbfd1831b6d591cd7100c188597c5"
|
|
25
25
|
},
|
|
26
26
|
"connector": {
|
|
27
27
|
"name": "ghcr.io/toon-protocol/connector",
|
|
28
|
-
"tag": "3.
|
|
29
|
-
"digest": "sha256:
|
|
28
|
+
"tag": "3.8.0",
|
|
29
|
+
"digest": "sha256:3343c19649290043e521c81b467b7c6410b8eaedd76d48804ea9b6fc810cddb0"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
}
|