@toon-protocol/townhouse 0.1.3 → 0.3.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.
@@ -6261,7 +6261,7 @@ function getDefaultConfig() {
6261
6261
  }
6262
6262
 
6263
6263
  // src/config/validator.ts
6264
- var VALID_CHAIN_TYPES = /* @__PURE__ */ new Set(["evm"]);
6264
+ var VALID_CHAIN_TYPES = /* @__PURE__ */ new Set(["evm", "solana", "mina"]);
6265
6265
  var HEX_ADDRESS = /^0x[a-fA-F0-9]+$/;
6266
6266
  var ConfigValidationError = class extends Error {
6267
6267
  constructor(message) {
@@ -6443,39 +6443,74 @@ function validateConfig(raw) {
6443
6443
  chainProviders = raw["chainProviders"].map((entry, idx) => {
6444
6444
  const path = `config.chainProviders[${idx}]`;
6445
6445
  assertObject(entry, path);
6446
- assertString(entry["chainType"], `${path}.chainType`);
6447
- if (!VALID_CHAIN_TYPES.has(entry["chainType"])) {
6446
+ const chainType = entry["chainType"];
6447
+ assertString(chainType, `${path}.chainType`);
6448
+ if (!VALID_CHAIN_TYPES.has(chainType)) {
6448
6449
  throw new ConfigValidationError(
6449
6450
  `${path}.chainType must be one of: ${[...VALID_CHAIN_TYPES].join(", ")}`
6450
6451
  );
6451
6452
  }
6452
6453
  assertString(entry["chainId"], `${path}.chainId`);
6453
- assertString(entry["rpcUrl"], `${path}.rpcUrl`);
6454
- assertString(entry["registryAddress"], `${path}.registryAddress`);
6455
- if (!HEX_ADDRESS.test(entry["registryAddress"])) {
6456
- throw new ConfigValidationError(
6457
- `${path}.registryAddress must match /^0x[a-fA-F0-9]+$/`
6458
- );
6454
+ if (chainType === "evm") {
6455
+ assertString(entry["rpcUrl"], `${path}.rpcUrl`);
6456
+ assertString(entry["registryAddress"], `${path}.registryAddress`);
6457
+ if (!HEX_ADDRESS.test(entry["registryAddress"])) {
6458
+ throw new ConfigValidationError(
6459
+ `${path}.registryAddress must match /^0x[a-fA-F0-9]+$/`
6460
+ );
6461
+ }
6462
+ assertString(entry["tokenAddress"], `${path}.tokenAddress`);
6463
+ if (!HEX_ADDRESS.test(entry["tokenAddress"])) {
6464
+ throw new ConfigValidationError(
6465
+ `${path}.tokenAddress must match /^0x[a-fA-F0-9]+$/`
6466
+ );
6467
+ }
6468
+ assertString(entry["keyId"], `${path}.keyId`);
6469
+ if (!HEX_ADDRESS.test(entry["keyId"])) {
6470
+ throw new ConfigValidationError(
6471
+ `${path}.keyId must match /^0x[a-fA-F0-9]+$/`
6472
+ );
6473
+ }
6474
+ return {
6475
+ chainType: "evm",
6476
+ chainId: entry["chainId"],
6477
+ rpcUrl: entry["rpcUrl"],
6478
+ registryAddress: entry["registryAddress"],
6479
+ tokenAddress: entry["tokenAddress"],
6480
+ keyId: entry["keyId"]
6481
+ };
6459
6482
  }
6460
- assertString(entry["tokenAddress"], `${path}.tokenAddress`);
6461
- if (!HEX_ADDRESS.test(entry["tokenAddress"])) {
6462
- throw new ConfigValidationError(
6463
- `${path}.tokenAddress must match /^0x[a-fA-F0-9]+$/`
6464
- );
6483
+ if (chainType === "solana") {
6484
+ assertString(entry["rpcUrl"], `${path}.rpcUrl`);
6485
+ assertString(entry["programId"], `${path}.programId`);
6486
+ assertString(entry["keyId"], `${path}.keyId`);
6487
+ if (entry["wsUrl"] !== void 0) {
6488
+ assertString(entry["wsUrl"], `${path}.wsUrl`);
6489
+ }
6490
+ if (entry["tokenMint"] !== void 0) {
6491
+ assertString(entry["tokenMint"], `${path}.tokenMint`);
6492
+ }
6493
+ return {
6494
+ chainType: "solana",
6495
+ chainId: entry["chainId"],
6496
+ rpcUrl: entry["rpcUrl"],
6497
+ ...entry["wsUrl"] !== void 0 ? { wsUrl: entry["wsUrl"] } : {},
6498
+ programId: entry["programId"],
6499
+ ...entry["tokenMint"] !== void 0 ? { tokenMint: entry["tokenMint"] } : {},
6500
+ keyId: entry["keyId"]
6501
+ };
6465
6502
  }
6466
- assertString(entry["keyId"], `${path}.keyId`);
6467
- if (!HEX_ADDRESS.test(entry["keyId"])) {
6468
- throw new ConfigValidationError(
6469
- `${path}.keyId must match /^0x[a-fA-F0-9]+$/`
6470
- );
6503
+ assertString(entry["graphqlUrl"], `${path}.graphqlUrl`);
6504
+ assertString(entry["zkAppAddress"], `${path}.zkAppAddress`);
6505
+ if (entry["keyId"] !== void 0) {
6506
+ assertString(entry["keyId"], `${path}.keyId`);
6471
6507
  }
6472
6508
  return {
6473
- chainType: entry["chainType"],
6509
+ chainType: "mina",
6474
6510
  chainId: entry["chainId"],
6475
- rpcUrl: entry["rpcUrl"],
6476
- registryAddress: entry["registryAddress"],
6477
- tokenAddress: entry["tokenAddress"],
6478
- keyId: entry["keyId"]
6511
+ graphqlUrl: entry["graphqlUrl"],
6512
+ zkAppAddress: entry["zkAppAddress"],
6513
+ ...entry["keyId"] !== void 0 ? { keyId: entry["keyId"] } : {}
6479
6514
  };
6480
6515
  });
6481
6516
  }
@@ -6740,14 +6775,36 @@ var ConnectorConfigGenerator = class {
6740
6775
  routes: []
6741
6776
  };
6742
6777
  if (this.config.chainProviders !== void 0 && this.config.chainProviders.length > 0) {
6743
- yamlObj["chainProviders"] = this.config.chainProviders.map((p) => ({
6744
- chainType: p.chainType,
6745
- chainId: p.chainId,
6746
- rpcUrl: p.rpcUrl,
6747
- registryAddress: p.registryAddress,
6748
- tokenAddress: p.tokenAddress,
6749
- keyId: p.keyId
6750
- }));
6778
+ yamlObj["chainProviders"] = this.config.chainProviders.map((p) => {
6779
+ if (p.chainType === "evm") {
6780
+ return {
6781
+ chainType: "evm",
6782
+ chainId: p.chainId,
6783
+ rpcUrl: p.rpcUrl,
6784
+ registryAddress: p.registryAddress,
6785
+ tokenAddress: p.tokenAddress,
6786
+ keyId: p.keyId
6787
+ };
6788
+ }
6789
+ if (p.chainType === "solana") {
6790
+ return {
6791
+ chainType: "solana",
6792
+ chainId: p.chainId,
6793
+ rpcUrl: p.rpcUrl,
6794
+ ...p.wsUrl !== void 0 ? { wsUrl: p.wsUrl } : {},
6795
+ programId: p.programId,
6796
+ ...p.tokenMint !== void 0 ? { tokenMint: p.tokenMint } : {},
6797
+ keyId: p.keyId
6798
+ };
6799
+ }
6800
+ return {
6801
+ chainType: "mina",
6802
+ chainId: p.chainId,
6803
+ graphqlUrl: p.graphqlUrl,
6804
+ zkAppAddress: p.zkAppAddress,
6805
+ ...p.keyId !== void 0 ? { keyId: p.keyId } : {}
6806
+ };
6807
+ });
6751
6808
  }
6752
6809
  return yamlStringify(yamlObj);
6753
6810
  }
@@ -21119,6 +21176,9 @@ function buildConfigFromRequest(request, configPath) {
21119
21176
  config.nodes.dvm.feePerJob = request.nodes.dvm.feePerJob;
21120
21177
  }
21121
21178
  config.transport.mode = request.transport.mode;
21179
+ if (request.chainProviders && request.chainProviders.length > 0) {
21180
+ config.chainProviders = request.chainProviders;
21181
+ }
21122
21182
  return config;
21123
21183
  }
21124
21184
 
@@ -21326,6 +21386,118 @@ function registerTransportRoutes(app, deps, opts = {}) {
21326
21386
  );
21327
21387
  }
21328
21388
 
21389
+ // src/api/routes/chains.ts
21390
+ var REDACTED = "***";
21391
+ function redactKeyId(providers) {
21392
+ return providers.map((p) => {
21393
+ const hasKey = p.keyId !== void 0;
21394
+ return hasKey ? { ...p, keyId: REDACTED } : { ...p };
21395
+ });
21396
+ }
21397
+ var patchBodySchema3 = {
21398
+ body: {
21399
+ type: "object",
21400
+ additionalProperties: false,
21401
+ required: ["chainProviders"],
21402
+ properties: {
21403
+ chainProviders: {
21404
+ type: "array",
21405
+ maxItems: 32,
21406
+ items: {
21407
+ type: "object",
21408
+ // Deep per-chain validation runs in validateConfig() below; keep the
21409
+ // JSON schema permissive about the discriminated fields, but pin the
21410
+ // discriminator + chainId so obviously-bad payloads fail fast.
21411
+ required: ["chainType", "chainId"],
21412
+ additionalProperties: true,
21413
+ properties: {
21414
+ chainType: { type: "string", enum: ["evm", "solana", "mina"] },
21415
+ chainId: { type: "string", minLength: 1, maxLength: 256 }
21416
+ }
21417
+ }
21418
+ }
21419
+ }
21420
+ }
21421
+ };
21422
+ function registerChainsRoutes(app, deps) {
21423
+ app.get("/api/chains", async (_request, reply) => {
21424
+ return reply.status(200).send({
21425
+ chainProviders: redactKeyId(deps.config.chainProviders ?? []),
21426
+ ts: Date.now()
21427
+ });
21428
+ });
21429
+ app.patch(
21430
+ "/api/chains",
21431
+ { schema: patchBodySchema3 },
21432
+ async (request, reply) => {
21433
+ const incoming = request.body.chainProviders;
21434
+ if (!acquireConfigMutex()) {
21435
+ return reply.status(409).send({ error: "config_mutation_in_flight" });
21436
+ }
21437
+ const prior = deps.config.chainProviders;
21438
+ const priorByChainId = new Map(
21439
+ (prior ?? []).map((p) => [p.chainId, p])
21440
+ );
21441
+ try {
21442
+ const merged = incoming.map((entry) => {
21443
+ const incomingKeyId = entry.keyId;
21444
+ if (incomingKeyId === void 0 || incomingKeyId === REDACTED) {
21445
+ const priorKeyId = priorByChainId.get(entry.chainId)?.keyId;
21446
+ if (priorKeyId !== void 0) {
21447
+ return { ...entry, keyId: priorKeyId };
21448
+ }
21449
+ if (incomingKeyId === REDACTED) {
21450
+ const { keyId: _drop, ...rest } = entry;
21451
+ return rest;
21452
+ }
21453
+ }
21454
+ return entry;
21455
+ });
21456
+ deps.config.chainProviders = merged.length > 0 ? merged : void 0;
21457
+ try {
21458
+ validateConfig(deps.config);
21459
+ } catch (validationError) {
21460
+ deps.config.chainProviders = prior;
21461
+ return reply.status(400).send({
21462
+ error: "config_validation_error",
21463
+ message: validationError instanceof Error ? validationError.message : "Invalid chain configuration"
21464
+ });
21465
+ }
21466
+ try {
21467
+ await saveConfig(deps.configPath, deps.config);
21468
+ } catch (saveError) {
21469
+ deps.config.chainProviders = prior;
21470
+ return reply.status(500).send({
21471
+ error: "config_save_failed",
21472
+ message: saveError instanceof Error ? saveError.message : "Failed to persist config"
21473
+ });
21474
+ }
21475
+ const activeNodes = Object.entries(deps.config.nodes).filter(([, cfg]) => cfg.enabled).map(([t]) => t);
21476
+ try {
21477
+ await deps.orchestrator.regenerateConnectorConfig(activeNodes);
21478
+ } catch (restartError) {
21479
+ deps.config.chainProviders = prior;
21480
+ try {
21481
+ await saveConfig(deps.configPath, deps.config);
21482
+ } catch {
21483
+ }
21484
+ return reply.status(500).send({
21485
+ error: "connector_restart_failed",
21486
+ message: restartError instanceof Error ? restartError.message : "Connector restart failed"
21487
+ });
21488
+ }
21489
+ return reply.status(200).send({
21490
+ chainProviders: redactKeyId(deps.config.chainProviders ?? []),
21491
+ restartTriggered: true,
21492
+ restartedAt: Date.now()
21493
+ });
21494
+ } finally {
21495
+ releaseConfigMutex();
21496
+ }
21497
+ }
21498
+ );
21499
+ }
21500
+
21329
21501
  // src/api/routes/earnings.ts
21330
21502
  import { dirname as dirname10, join as join8 } from "path";
21331
21503
 
@@ -21813,6 +21985,7 @@ async function createApiServer(deps) {
21813
21985
  { mode: "normal" }
21814
21986
  );
21815
21987
  registerTransportRoutes(app, deps);
21988
+ registerChainsRoutes(app, deps);
21816
21989
  registerNodeRoutes(app, deps);
21817
21990
  registerWalletRoutes(app, deps);
21818
21991
  registerWalletBalancesRoutes(app, deps);
@@ -22114,4 +22287,4 @@ export {
22114
22287
  @scure/bip32/index.js:
22115
22288
  (*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
22116
22289
  */
22117
- //# sourceMappingURL=chunk-QHFUIWEN.js.map
22290
+ //# sourceMappingURL=chunk-B4KWPVEK.js.map