@toon-protocol/townhouse 0.1.2 → 0.2.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/dist/{chunk-W33MEOPM.js → chunk-B4KWPVEK.js} +219 -40
- package/dist/chunk-B4KWPVEK.js.map +1 -0
- package/dist/cli.d.ts +1 -7
- package/dist/cli.js +227 -44
- package/dist/cli.js.map +1 -1
- package/dist/compose/townhouse-hs.yml +8 -8
- package/dist/image-manifest.json +10 -10
- package/dist/index.d.ts +9 -3
- package/dist/index.js +1 -1
- package/dist/{manager-SsneW_Mj.d.ts → manager-BtpOFwd6.d.ts} +44 -8
- package/dist/{tui-OIFXGBTL.js → tui-QE3ZRZO3.js} +21 -8
- package/dist/tui-QE3ZRZO3.js.map +1 -0
- package/package.json +3 -3
- package/dist/chunk-W33MEOPM.js.map +0 -1
- package/dist/tui-OIFXGBTL.js.map +0 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import Docker from 'dockerode';
|
|
3
|
-
import { C as ComposeLoaderOptions, T as TownhouseConfig, W as WalletManager, N as NodeType } from './manager-
|
|
3
|
+
import { C as ComposeLoaderOptions, T as TownhouseConfig, W as WalletManager, N as NodeType } from './manager-BtpOFwd6.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Cross-platform browser opener for the wizard CLI command.
|
|
@@ -119,12 +119,6 @@ interface CliNodeCommandOverrides {
|
|
|
119
119
|
confirm?: (question: string) => Promise<boolean>;
|
|
120
120
|
apiUrl?: string;
|
|
121
121
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Main CLI entry — exported for testability (same pattern as Mill CLI).
|
|
124
|
-
* Accepts optional dockerode instance for dependency injection in tests.
|
|
125
|
-
* The optional `hsOverrides` bag is used by unit tests to stub out Docker,
|
|
126
|
-
* file I/O, and admin-client calls in the `hs up` / `hs down` path.
|
|
127
|
-
*/
|
|
128
122
|
declare function main(argv: string[], dockerInstance?: Docker, browserOpener?: BrowserOpener, hsOverrides?: CliHsOverrides, nodeCommandOverrides?: CliNodeCommandOverrides): Promise<void>;
|
|
129
123
|
|
|
130
124
|
export { CliHelpRequested, type CliHsOverrides, type CliNodeCommandOverrides, main };
|
package/dist/cli.js
CHANGED
|
@@ -23,11 +23,12 @@ import {
|
|
|
23
23
|
materializeComposeTemplate,
|
|
24
24
|
readImageManifest,
|
|
25
25
|
readNodesYaml,
|
|
26
|
+
saveConfig,
|
|
26
27
|
saveWallet,
|
|
27
28
|
serviceFromContainerName,
|
|
28
29
|
tailContainerLogs,
|
|
29
30
|
writeHsConnectorConfig
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-B4KWPVEK.js";
|
|
31
32
|
import "./chunk-5O4SBV5O.js";
|
|
32
33
|
import {
|
|
33
34
|
CONTAINER_PREFIX
|
|
@@ -2004,6 +2005,9 @@ Usage:
|
|
|
2004
2005
|
townhouse node add [<type>] [--json] [-c <path>] Provision a child node (default: town)
|
|
2005
2006
|
townhouse node remove <id> [--yes] [--json] [-c <path>] Deprovision a child node
|
|
2006
2007
|
townhouse node list [--json] [-c <path>] List provisioned nodes
|
|
2008
|
+
townhouse chains list [--json] [-c <path>] List configured settlement chains (EVM/Solana/Mina)
|
|
2009
|
+
townhouse chains add --chain-type <evm|solana|mina> --chain-id <id> [fields] [-c <path>] Add/update a settlement chain
|
|
2010
|
+
townhouse chains remove <chainId> [-c <path>] Remove a settlement chain
|
|
2007
2011
|
townhouse channels [--json] Show open payment channels
|
|
2008
2012
|
townhouse logs <node-id> [-f|--follow] [--lines N] [--json] Tail logs for a node (Ctrl-C to stop)
|
|
2009
2013
|
townhouse peer <id> [--json] Show per-peer detail card
|
|
@@ -3029,8 +3033,52 @@ function isAnonBootstrapTimeout(err) {
|
|
|
3029
3033
|
${err.stderr ?? ""}`;
|
|
3030
3034
|
return /connector.*unhealthy|dependency.*connector.*fail/i.test(text);
|
|
3031
3035
|
}
|
|
3036
|
+
async function attachDashboard(hostname) {
|
|
3037
|
+
if (!shouldRenderInk()) return;
|
|
3038
|
+
try {
|
|
3039
|
+
const { mountTui } = await import("./tui-QE3ZRZO3.js");
|
|
3040
|
+
const apiUrlOverride = process.env["HS_TOWNHOUSE_API_URL"];
|
|
3041
|
+
const mountOpts = apiUrlOverride !== void 0 ? { apiUrl: apiUrlOverride } : {};
|
|
3042
|
+
const instance = mountTui(mountOpts);
|
|
3043
|
+
await instance.waitUntilExit();
|
|
3044
|
+
} catch (tuiErr) {
|
|
3045
|
+
const detail = tuiErr instanceof Error ? tuiErr.message : String(tuiErr);
|
|
3046
|
+
console.error("");
|
|
3047
|
+
console.error(`Your node is live at ${hostname}.`);
|
|
3048
|
+
console.error(
|
|
3049
|
+
`The live dashboard could not open (${detail}) \u2014 this is a display issue, not a node issue. Your node keeps running.`
|
|
3050
|
+
);
|
|
3051
|
+
console.error(
|
|
3052
|
+
"Stop it anytime with: npx @toon-protocol/townhouse hs down"
|
|
3053
|
+
);
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3032
3056
|
async function handleHsUp(_configPath, configDir, config, docker, options) {
|
|
3033
3057
|
const { password, force, skipPreflight, hsOverrides } = options;
|
|
3058
|
+
if (!force) {
|
|
3059
|
+
const adminClientFactory = hsOverrides?.createAdminClient ?? ((url, t) => new ConnectorAdminClient(url, t));
|
|
3060
|
+
const probe = adminClientFactory(HS_CONNECTOR_ADMIN_URL, 3e3);
|
|
3061
|
+
try {
|
|
3062
|
+
const existing = await probe.getHsHostname();
|
|
3063
|
+
if (existing.hostname !== null) {
|
|
3064
|
+
console.log(`Apex live at ${existing.hostname}`);
|
|
3065
|
+
_writeHostJson(configDir, {
|
|
3066
|
+
hostname: existing.hostname,
|
|
3067
|
+
publishedAt: existing.publishedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3068
|
+
writtenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3069
|
+
});
|
|
3070
|
+
await attachDashboard(existing.hostname);
|
|
3071
|
+
return;
|
|
3072
|
+
}
|
|
3073
|
+
} catch (probeErr) {
|
|
3074
|
+
const msg = probeErr instanceof Error ? probeErr.message : String(probeErr);
|
|
3075
|
+
if (msg.includes("anon-disabled")) {
|
|
3076
|
+
const { exitCode } = renderFailure(probeErr);
|
|
3077
|
+
process.exitCode = exitCode;
|
|
3078
|
+
return;
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3034
3082
|
if (!skipPreflight) {
|
|
3035
3083
|
const preflight = hsOverrides?.checkPortCollisions ?? ((d) => checkHsPortCollisions(d));
|
|
3036
3084
|
try {
|
|
@@ -3089,29 +3137,6 @@ async function handleHsUp(_configPath, configDir, config, docker, options) {
|
|
|
3089
3137
|
}
|
|
3090
3138
|
const ribbon = new OnboardingRibbon();
|
|
3091
3139
|
try {
|
|
3092
|
-
if (!force) {
|
|
3093
|
-
const adminClientFactory = hsOverrides?.createAdminClient ?? ((url, t) => new ConnectorAdminClient(url, t));
|
|
3094
|
-
const probe = adminClientFactory(HS_CONNECTOR_ADMIN_URL, 3e3);
|
|
3095
|
-
try {
|
|
3096
|
-
const existing = await probe.getHsHostname();
|
|
3097
|
-
if (existing.hostname !== null) {
|
|
3098
|
-
console.log(`Apex live at ${existing.hostname}`);
|
|
3099
|
-
_writeHostJson(configDir, {
|
|
3100
|
-
hostname: existing.hostname,
|
|
3101
|
-
publishedAt: existing.publishedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3102
|
-
writtenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3103
|
-
});
|
|
3104
|
-
return;
|
|
3105
|
-
}
|
|
3106
|
-
} catch (probeErr) {
|
|
3107
|
-
const msg = probeErr instanceof Error ? probeErr.message : String(probeErr);
|
|
3108
|
-
if (msg.includes("anon-disabled")) {
|
|
3109
|
-
const { exitCode } = renderFailure(probeErr);
|
|
3110
|
-
process.exitCode = exitCode;
|
|
3111
|
-
return;
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
}
|
|
3115
3140
|
writeHsConnectorConfig(configDir, config, { force });
|
|
3116
3141
|
const materialize = hsOverrides?.materializeComposeTemplate ?? materializeComposeTemplate;
|
|
3117
3142
|
const { composePath } = materialize("hs", { townhouseHome: configDir });
|
|
@@ -3141,6 +3166,7 @@ async function handleHsUp(_configPath, configDir, config, docker, options) {
|
|
|
3141
3166
|
ribbon.start("bootstrap");
|
|
3142
3167
|
}
|
|
3143
3168
|
});
|
|
3169
|
+
ribbon.stop();
|
|
3144
3170
|
if (typeof orch.pullImage === "function") {
|
|
3145
3171
|
try {
|
|
3146
3172
|
const apexImages = await collectApexImageRefs(configDir);
|
|
@@ -3263,25 +3289,7 @@ async function handleHsUp(_configPath, configDir, config, docker, options) {
|
|
|
3263
3289
|
writtenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3264
3290
|
});
|
|
3265
3291
|
ribbon.start("live", hostname);
|
|
3266
|
-
|
|
3267
|
-
try {
|
|
3268
|
-
const { mountTui } = await import("./tui-OIFXGBTL.js");
|
|
3269
|
-
const apiUrlOverride = process.env["HS_TOWNHOUSE_API_URL"];
|
|
3270
|
-
const mountOpts = apiUrlOverride !== void 0 ? { apiUrl: apiUrlOverride } : {};
|
|
3271
|
-
const instance = mountTui(mountOpts);
|
|
3272
|
-
await instance.waitUntilExit();
|
|
3273
|
-
} catch (tuiErr) {
|
|
3274
|
-
const detail = tuiErr instanceof Error ? tuiErr.message : String(tuiErr);
|
|
3275
|
-
console.error("");
|
|
3276
|
-
console.error(`Your node is live at ${hostname}.`);
|
|
3277
|
-
console.error(
|
|
3278
|
-
`The live dashboard could not open (${detail}) \u2014 this is a display issue, not a node issue. Your node keeps running.`
|
|
3279
|
-
);
|
|
3280
|
-
console.error(
|
|
3281
|
-
"Stop it anytime with: npx @toon-protocol/townhouse hs down"
|
|
3282
|
-
);
|
|
3283
|
-
}
|
|
3284
|
-
}
|
|
3292
|
+
await attachDashboard(hostname);
|
|
3285
3293
|
} catch (err) {
|
|
3286
3294
|
const { exitCode } = renderFailure(err);
|
|
3287
3295
|
process.exitCode = exitCode;
|
|
@@ -3439,6 +3447,143 @@ function _runDockerComposeDown(composePath, withVolumes) {
|
|
|
3439
3447
|
});
|
|
3440
3448
|
});
|
|
3441
3449
|
}
|
|
3450
|
+
var CHAINS_HELP = `townhouse chains \u2014 configure settlement chains (connector chainProviders)
|
|
3451
|
+
|
|
3452
|
+
The connector settles ILP payment claims on these chains. Changes take effect
|
|
3453
|
+
on the next 'townhouse hs down && townhouse hs up'.
|
|
3454
|
+
|
|
3455
|
+
Usage:
|
|
3456
|
+
townhouse chains list [--json] [-c <path>]
|
|
3457
|
+
townhouse chains add --chain-type <evm|solana|mina> --chain-id <id> [fields] [-c <path>]
|
|
3458
|
+
townhouse chains remove <chainId> [-c <path>]
|
|
3459
|
+
|
|
3460
|
+
Fields by chain type:
|
|
3461
|
+
evm: --rpc-url <url> --registry <0x..> --token-address <0x..> --key-id <0x..>
|
|
3462
|
+
solana: --rpc-url <url> --program-id <addr> --key-id <id> [--ws-url <url>] [--token-mint <addr>]
|
|
3463
|
+
mina: --graphql-url <url> --zkapp <addr> [--key-id <id>]`;
|
|
3464
|
+
function buildChainProviderFromFlags(f) {
|
|
3465
|
+
const { chainType, chainId } = f;
|
|
3466
|
+
if (chainType !== "evm" && chainType !== "solana" && chainType !== "mina") {
|
|
3467
|
+
throw new Error("--chain-type must be one of: evm, solana, mina");
|
|
3468
|
+
}
|
|
3469
|
+
if (!chainId) throw new Error("--chain-id is required");
|
|
3470
|
+
const require2 = (flag, val) => {
|
|
3471
|
+
if (!val) throw new Error(`${flag} is required for ${chainType} chains`);
|
|
3472
|
+
return val;
|
|
3473
|
+
};
|
|
3474
|
+
if (chainType === "evm") {
|
|
3475
|
+
return {
|
|
3476
|
+
chainType: "evm",
|
|
3477
|
+
chainId,
|
|
3478
|
+
rpcUrl: require2("--rpc-url", f.rpcUrl),
|
|
3479
|
+
registryAddress: require2("--registry", f.registry),
|
|
3480
|
+
tokenAddress: require2("--token-address", f.tokenAddress),
|
|
3481
|
+
keyId: require2("--key-id", f.keyId)
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
if (chainType === "solana") {
|
|
3485
|
+
return {
|
|
3486
|
+
chainType: "solana",
|
|
3487
|
+
chainId,
|
|
3488
|
+
rpcUrl: require2("--rpc-url", f.rpcUrl),
|
|
3489
|
+
...f.wsUrl ? { wsUrl: f.wsUrl } : {},
|
|
3490
|
+
programId: require2("--program-id", f.programId),
|
|
3491
|
+
...f.tokenMint ? { tokenMint: f.tokenMint } : {},
|
|
3492
|
+
keyId: require2("--key-id", f.keyId)
|
|
3493
|
+
};
|
|
3494
|
+
}
|
|
3495
|
+
return {
|
|
3496
|
+
chainType: "mina",
|
|
3497
|
+
chainId,
|
|
3498
|
+
graphqlUrl: require2("--graphql-url", f.graphqlUrl),
|
|
3499
|
+
zkAppAddress: require2("--zkapp", f.zkapp),
|
|
3500
|
+
...f.keyId ? { keyId: f.keyId } : {}
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3503
|
+
async function handleChains(action, chainIdArg, flags, configPath, jsonMode) {
|
|
3504
|
+
if (!action) {
|
|
3505
|
+
console.log(CHAINS_HELP);
|
|
3506
|
+
throw new CliHelpRequested();
|
|
3507
|
+
}
|
|
3508
|
+
const config = loadConfig(configPath);
|
|
3509
|
+
const providers = config.chainProviders ?? [];
|
|
3510
|
+
switch (action) {
|
|
3511
|
+
case "list": {
|
|
3512
|
+
if (jsonMode) {
|
|
3513
|
+
console.log(JSON.stringify(providers, null, 2));
|
|
3514
|
+
return;
|
|
3515
|
+
}
|
|
3516
|
+
if (providers.length === 0) {
|
|
3517
|
+
console.log(
|
|
3518
|
+
"No settlement chains configured \u2014 the connector uses a built-in dev-Anvil EVM placeholder."
|
|
3519
|
+
);
|
|
3520
|
+
console.log(
|
|
3521
|
+
"Add one with: townhouse chains add --chain-type evm --chain-id evm:base:8453 ..."
|
|
3522
|
+
);
|
|
3523
|
+
return;
|
|
3524
|
+
}
|
|
3525
|
+
console.log("Configured settlement chains:");
|
|
3526
|
+
for (const p of providers) {
|
|
3527
|
+
console.log(` ${p.chainType.padEnd(6)} ${p.chainId}`);
|
|
3528
|
+
}
|
|
3529
|
+
return;
|
|
3530
|
+
}
|
|
3531
|
+
case "add": {
|
|
3532
|
+
let entry;
|
|
3533
|
+
try {
|
|
3534
|
+
entry = buildChainProviderFromFlags(flags);
|
|
3535
|
+
} catch (err) {
|
|
3536
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
3537
|
+
process.exitCode = 1;
|
|
3538
|
+
return;
|
|
3539
|
+
}
|
|
3540
|
+
const next = providers.filter((p) => p.chainId !== entry.chainId);
|
|
3541
|
+
next.push(entry);
|
|
3542
|
+
try {
|
|
3543
|
+
saveConfig(configPath, { ...config, chainProviders: next });
|
|
3544
|
+
} catch (err) {
|
|
3545
|
+
console.error(
|
|
3546
|
+
`Invalid chain config: ${err instanceof Error ? err.message : String(err)}`
|
|
3547
|
+
);
|
|
3548
|
+
process.exitCode = 1;
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
console.log(
|
|
3552
|
+
`Added ${entry.chainType} settlement chain '${entry.chainId}'.`
|
|
3553
|
+
);
|
|
3554
|
+
console.log("Apply with: townhouse hs down && townhouse hs up");
|
|
3555
|
+
return;
|
|
3556
|
+
}
|
|
3557
|
+
case "remove": {
|
|
3558
|
+
if (!chainIdArg) {
|
|
3559
|
+
console.error("Usage: townhouse chains remove <chainId>");
|
|
3560
|
+
process.exitCode = 1;
|
|
3561
|
+
return;
|
|
3562
|
+
}
|
|
3563
|
+
const next = providers.filter((p) => p.chainId !== chainIdArg);
|
|
3564
|
+
if (next.length === providers.length) {
|
|
3565
|
+
console.error(
|
|
3566
|
+
`No settlement chain with chainId '${chainIdArg}' found.`
|
|
3567
|
+
);
|
|
3568
|
+
process.exitCode = 1;
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
saveConfig(configPath, {
|
|
3572
|
+
...config,
|
|
3573
|
+
chainProviders: next.length > 0 ? next : void 0
|
|
3574
|
+
});
|
|
3575
|
+
console.log(`Removed settlement chain '${chainIdArg}'.`);
|
|
3576
|
+
console.log("Apply with: townhouse hs down && townhouse hs up");
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
default: {
|
|
3580
|
+
const safe = action.replace(/[\x00-\x1f\x7f]/g, "");
|
|
3581
|
+
console.error(`Unknown chains subcommand: ${safe}`);
|
|
3582
|
+
console.log(CHAINS_HELP);
|
|
3583
|
+
process.exitCode = 1;
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
3442
3587
|
async function main(argv, dockerInstance, browserOpener, hsOverrides, nodeCommandOverrides) {
|
|
3443
3588
|
const { values, positionals } = parseArgs({
|
|
3444
3589
|
args: argv,
|
|
@@ -3473,7 +3618,19 @@ async function main(argv, dockerInstance, browserOpener, hsOverrides, nodeComman
|
|
|
3473
3618
|
// wallet show / wallet seed (epic-49, Phase 3)
|
|
3474
3619
|
hex: { type: "boolean" },
|
|
3475
3620
|
paths: { type: "boolean" },
|
|
3476
|
-
confirm: { type: "boolean" }
|
|
3621
|
+
confirm: { type: "boolean" },
|
|
3622
|
+
// chains add (multi-chain settlement config)
|
|
3623
|
+
"chain-type": { type: "string" },
|
|
3624
|
+
"chain-id": { type: "string" },
|
|
3625
|
+
"rpc-url": { type: "string" },
|
|
3626
|
+
"ws-url": { type: "string" },
|
|
3627
|
+
registry: { type: "string" },
|
|
3628
|
+
"token-address": { type: "string" },
|
|
3629
|
+
"token-mint": { type: "string" },
|
|
3630
|
+
"program-id": { type: "string" },
|
|
3631
|
+
"graphql-url": { type: "string" },
|
|
3632
|
+
zkapp: { type: "string" },
|
|
3633
|
+
"key-id": { type: "string" }
|
|
3477
3634
|
},
|
|
3478
3635
|
strict: false,
|
|
3479
3636
|
allowPositionals: true
|
|
@@ -3708,6 +3865,32 @@ async function main(argv, dockerInstance, browserOpener, hsOverrides, nodeComman
|
|
|
3708
3865
|
}
|
|
3709
3866
|
break;
|
|
3710
3867
|
}
|
|
3868
|
+
case "chains": {
|
|
3869
|
+
const configPath = values.config ?? DEFAULT_CONFIG_PATH;
|
|
3870
|
+
const action = positionals[1];
|
|
3871
|
+
const chainIdArg = positionals[2];
|
|
3872
|
+
const flags = {
|
|
3873
|
+
chainType: values["chain-type"],
|
|
3874
|
+
chainId: values["chain-id"],
|
|
3875
|
+
rpcUrl: values["rpc-url"],
|
|
3876
|
+
wsUrl: values["ws-url"],
|
|
3877
|
+
registry: values["registry"],
|
|
3878
|
+
tokenAddress: values["token-address"],
|
|
3879
|
+
tokenMint: values["token-mint"],
|
|
3880
|
+
programId: values["program-id"],
|
|
3881
|
+
graphqlUrl: values["graphql-url"],
|
|
3882
|
+
zkapp: values["zkapp"],
|
|
3883
|
+
keyId: values["key-id"]
|
|
3884
|
+
};
|
|
3885
|
+
await handleChains(
|
|
3886
|
+
action,
|
|
3887
|
+
chainIdArg,
|
|
3888
|
+
flags,
|
|
3889
|
+
configPath,
|
|
3890
|
+
values.json === true
|
|
3891
|
+
);
|
|
3892
|
+
break;
|
|
3893
|
+
}
|
|
3711
3894
|
default: {
|
|
3712
3895
|
const sanitized = command.replace(/[\x00-\x1f\x7f]/g, "");
|
|
3713
3896
|
console.error(`Unknown command: ${sanitized}`);
|