@atbash/sdk 0.12.0-dev.0 → 0.13.0-dev.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/index.mjs CHANGED
@@ -3313,11 +3313,34 @@ var ENV_MAP = {
3313
3313
  judgeEndpoint: "ATBASH_ENDPOINT",
3314
3314
  // Same variable name the Hermes plugin already documents.
3315
3315
  judgeVerifyPubKey: "ATBASH_JUDGE_VERIFY_PUBKEY",
3316
- blockchainRid: "ATBASH_BLOCKCHAIN_RID",
3316
+ defaultChainNetwork: "ATBASH_DEFAULT_CHAIN_NETWORK",
3317
3317
  provider: "ATBASH_PROVIDER",
3318
3318
  providerModel: "ATBASH_PROVIDER_MODEL",
3319
3319
  debug: "ATBASH_DEBUG"
3320
3320
  };
3321
+ var DEPRECATED_ENV_VARS = ["ATBASH_BLOCKCHAIN_RID"];
3322
+ var DEPRECATED_CONFIG_FIELDS = ["blockchainRid"];
3323
+ var deprecatedWarned = false;
3324
+ function warnDeprecatedEnvVarsOnce(log = console.warn) {
3325
+ if (deprecatedWarned) return;
3326
+ for (const name2 of DEPRECATED_ENV_VARS) {
3327
+ if (process.env[name2]) {
3328
+ deprecatedWarned = true;
3329
+ log(
3330
+ `[atbash] ${name2} is ignored \u2014 each org's chain is resolved from the dashboard; set ATBASH_DEFAULT_CHAIN_NETWORK=private only to pin everything to private`
3331
+ );
3332
+ }
3333
+ }
3334
+ const fileConfig = loadUserConfig();
3335
+ for (const field of DEPRECATED_CONFIG_FIELDS) {
3336
+ if (fileConfig[field]) {
3337
+ deprecatedWarned = true;
3338
+ log(
3339
+ `[atbash] "${field}" in ${getConfigPath()} is ignored \u2014 pass \`chain\` or \`network\` at construction instead`
3340
+ );
3341
+ }
3342
+ }
3343
+ }
3321
3344
  function getConfigDir() {
3322
3345
  const home2 = process.env.HOME || homedir3() || "";
3323
3346
  return join3(home2, ".config", "atbash");
@@ -3359,11 +3382,41 @@ function resolve(key3, flagValue) {
3359
3382
  if (fileVal != null) return String(fileVal);
3360
3383
  return "";
3361
3384
  }
3385
+ function forcedChainNetwork(flagValue) {
3386
+ const raw2 = resolve("defaultChainNetwork", flagValue);
3387
+ if (!raw2) return void 0;
3388
+ if (raw2 !== "public" && raw2 !== "private") {
3389
+ throw new Error(
3390
+ `ATBASH_DEFAULT_CHAIN_NETWORK / defaultChainNetwork must be "public" or "private", got ${JSON.stringify(raw2)} \u2014 unset it to let each org's chain decide.`
3391
+ );
3392
+ }
3393
+ return raw2;
3394
+ }
3362
3395
 
3363
3396
  // src-ts/client.ts
3364
3397
  function generateToolCallId() {
3365
3398
  return `tc-${Date.now()}-${randomHex(4)}`;
3366
3399
  }
3400
+ function resolveConstructorChain(options) {
3401
+ if (options.chain) return options.chain;
3402
+ const hasNodeUrls = options.nodeUrls !== void 0;
3403
+ const hasBrid = options.blockchainRid !== void 0;
3404
+ if (hasNodeUrls !== hasBrid) {
3405
+ throw new Error(
3406
+ 'nodeUrls and blockchainRid must be provided together \u2014 passing one without the other 404s every chain request. Prefer `chain: PUBLIC_CHAIN | PRIVATE_CHAIN` or `network: "public" | "private"`.'
3407
+ );
3408
+ }
3409
+ if (hasNodeUrls && hasBrid) {
3410
+ const brid = options.blockchainRid;
3411
+ const derivedNetwork = options.network ?? (brid === PUBLIC_CHAIN.blockchainRid ? "public" : brid === PRIVATE_CHAIN.blockchainRid ? "private" : "private");
3412
+ return {
3413
+ network: derivedNetwork,
3414
+ blockchainRid: brid,
3415
+ nodeUrls: options.nodeUrls
3416
+ };
3417
+ }
3418
+ return chainForNetwork(options.network ?? forcedChainNetwork() ?? "private");
3419
+ }
3367
3420
  var Atbash = class _Atbash {
3368
3421
  auth;
3369
3422
  endpoint;
@@ -3387,6 +3440,27 @@ var Atbash = class _Atbash {
3387
3440
  * calls don't re-hit the dashboard. Cleared by `clearChainCache()`.
3388
3441
  */
3389
3442
  _chainCache = /* @__PURE__ */ new Map();
3443
+ /**
3444
+ * The chain the constructor settled on. Used only where a lookup returns no
3445
+ * answer — see {@link resolveChainFromMap}.
3446
+ */
3447
+ _defaultChain;
3448
+ /**
3449
+ * True when the caller named a chain outright — `chain`, `network`, or the
3450
+ * paired `blockchainRid` + `nodeUrls`.
3451
+ *
3452
+ * Such a client is never re-pointed: not by the migration switch, and not by
3453
+ * where an org turns out to live. Naming a chain is the caller saying "talk
3454
+ * to this one", and silently routing elsewhere would make the argument a
3455
+ * suggestion. A client that names nothing is the one that follows the org.
3456
+ */
3457
+ _explicitChain;
3458
+ /**
3459
+ * The fleet-wide chain switch, read once at construction. `resolve()` hits
3460
+ * the config file on disk, so re-reading it per call would put a file read
3461
+ * on every judge.
3462
+ */
3463
+ _forcedNetwork;
3390
3464
  /**
3391
3465
  * Short-TTL cache for `/api/ai/exists`. The `registered` field is
3392
3466
  * monotonic (once true, stays true), so most calls in a burst re-fetch
@@ -3419,8 +3493,13 @@ var Atbash = class _Atbash {
3419
3493
  } : { endpoint: options.endpoint }
3420
3494
  );
3421
3495
  this.endpoint = validated.url;
3422
- this.nodeUrls = options.nodeUrls ? [...options.nodeUrls] : DEFAULT_CHROMIA_NODE_URLS;
3423
- this.blockchainRid = options.blockchainRid ?? native.DEFAULT_BLOCKCHAIN_RID;
3496
+ const resolvedChain = resolveConstructorChain(options);
3497
+ this.nodeUrls = [...resolvedChain.nodeUrls];
3498
+ this.blockchainRid = resolvedChain.blockchainRid;
3499
+ this._defaultChain = resolvedChain;
3500
+ this._explicitChain = options.chain !== void 0 || options.network !== void 0 || options.blockchainRid !== void 0 && options.nodeUrls !== void 0;
3501
+ this._forcedNetwork = forcedChainNetwork();
3502
+ warnDeprecatedEnvVarsOnce((msg) => options.logger?.warn?.(msg));
3424
3503
  this.orgName = options.orgName;
3425
3504
  this.verifyPubKey = validated.verifyPubKey ?? void 0;
3426
3505
  this.orgEncryptionPubKey = options.orgEncryptionPubKey;
@@ -3496,10 +3575,11 @@ var Atbash = class _Atbash {
3496
3575
  );
3497
3576
  const agentKey = resolve("agentKey", options.agentKey);
3498
3577
  const auth = agentKey ? native.loadAgent(agentKey) : loadAgentFromFile(options.keyPath);
3499
- const blockchainRid = resolve("blockchainRid", options.blockchainRid) || void 0;
3500
3578
  return new _Atbash(auth.privkey, {
3501
3579
  endpoint: validated.url,
3502
- blockchainRid,
3580
+ chain: options.chain,
3581
+ network: options.network,
3582
+ blockchainRid: options.blockchainRid,
3503
3583
  timeoutMs: options.timeoutMs,
3504
3584
  nodeUrls: options.nodeUrls,
3505
3585
  orgName: options.orgName,
@@ -3540,7 +3620,7 @@ var Atbash = class _Atbash {
3540
3620
  return this.track("checkAgentExists", pk, async () => {
3541
3621
  const query = { pubkey: pk };
3542
3622
  if (network) query.network = network;
3543
- const brid = this.bridFromChainOpts(network ? { network } : void 0);
3623
+ const brid = network ? this.bridFromChainOpts({ network }) : await this.defaultOrgBrid();
3544
3624
  const resp = await this.http.get(
3545
3625
  "/api/ai/exists",
3546
3626
  query,
@@ -3591,7 +3671,7 @@ var Atbash = class _Atbash {
3591
3671
  };
3592
3672
  }
3593
3673
  const toolCallId = generateToolCallId();
3594
- const brid = this.bridFromChainOpts(options.chainOpts);
3674
+ const brid = options.chainOpts?.blockchainRid || options.chainOpts?.network ? this.bridFromChainOpts(options.chainOpts) : await this.defaultOrgBrid() ?? this.blockchainRid;
3595
3675
  const orgKey = options.orgEncryptionPubKey ?? this.orgEncryptionPubKey ?? this._orgKeyFromChain;
3596
3676
  try {
3597
3677
  const signedHex = orgKey ? signEncryptedToolCall(
@@ -3642,7 +3722,11 @@ var Atbash = class _Atbash {
3642
3722
  throw new Error("action is required and cannot be empty.");
3643
3723
  }
3644
3724
  let chainOpts = options.chainOpts;
3645
- if (options.orgName) {
3725
+ if (options.orgName && this._explicitChain) {
3726
+ chainOpts = options.chainOpts ?? { network: this._defaultChain.network };
3727
+ } else if (options.orgName && this.forcedNetwork()) {
3728
+ chainOpts = { network: this.forcedNetwork() };
3729
+ } else if (options.orgName) {
3646
3730
  const cached = this._chainCache.get(options.orgName);
3647
3731
  if (cached) {
3648
3732
  chainOpts = { network: cached.network };
@@ -3876,7 +3960,7 @@ var Atbash = class _Atbash {
3876
3960
  const resp = await this.http.get(
3877
3961
  "/api/v1/judge",
3878
3962
  { tool_call_id: judgmentId, agent_pubkey: pk },
3879
- this.authHeaders()
3963
+ this.authHeaders(await this.defaultOrgBrid())
3880
3964
  );
3881
3965
  await this.raiseIfError(resp);
3882
3966
  const data = await this.json(resp) ?? {};
@@ -3896,7 +3980,11 @@ var Atbash = class _Atbash {
3896
3980
  return this.track(
3897
3981
  "getToolCalls",
3898
3982
  void 0,
3899
- () => this.riskEngineRecords("tool-calls", { limit: maxCount })
3983
+ async () => this.riskEngineRecords(
3984
+ "tool-calls",
3985
+ { limit: maxCount },
3986
+ await this.defaultOrgBrid()
3987
+ )
3900
3988
  );
3901
3989
  }
3902
3990
  async getOrgToolCalls(orgName, maxCount) {
@@ -3913,24 +4001,31 @@ var Atbash = class _Atbash {
3913
4001
  return this.track(
3914
4002
  "getAgentToolCalls",
3915
4003
  agentPubkey,
3916
- () => this.riskEngineRecords("agent-tool-calls", {
3917
- agent: agentPubkey,
3918
- limit: maxCount
3919
- })
4004
+ async () => this.riskEngineRecords(
4005
+ "agent-tool-calls",
4006
+ { agent: agentPubkey, limit: maxCount },
4007
+ await this.defaultOrgBrid()
4008
+ )
3920
4009
  );
3921
4010
  }
3922
4011
  async getToolCallCount() {
3923
4012
  return this.track("getToolCallCount", void 0, async () => {
3924
- const raw2 = await this.riskEngineGet("tool-call-count", {});
4013
+ const raw2 = await this.riskEngineGet(
4014
+ "tool-call-count",
4015
+ {},
4016
+ await this.defaultOrgBrid()
4017
+ );
3925
4018
  const n = Number(raw2);
3926
4019
  return Number.isFinite(n) ? n : 0;
3927
4020
  });
3928
4021
  }
3929
4022
  async getToolCallFull(toolCallId) {
3930
4023
  return this.track("getToolCallFull", void 0, async () => {
3931
- const raw2 = await this.riskEngineGet("tool-call-full", {
3932
- tool_call_id: toolCallId
3933
- });
4024
+ const raw2 = await this.riskEngineGet(
4025
+ "tool-call-full",
4026
+ { tool_call_id: toolCallId },
4027
+ await this.defaultOrgBrid()
4028
+ );
3934
4029
  if (!isRecord(raw2)) return null;
3935
4030
  return toToolCallFull(raw2);
3936
4031
  });
@@ -4016,7 +4111,7 @@ var Atbash = class _Atbash {
4016
4111
  const resp = await this.http.get(
4017
4112
  "/api/insurance",
4018
4113
  { action: "safety-stats" },
4019
- this.authHeaders()
4114
+ this.authHeaders(await this.defaultOrgBrid())
4020
4115
  );
4021
4116
  await this.raiseIfError(resp);
4022
4117
  const data = await this.json(resp) ?? {};
@@ -4072,10 +4167,15 @@ var Atbash = class _Atbash {
4072
4167
  * 2. Per-chain subscription fallback — public + private records
4073
4168
  * are fetched in parallel, with `is_private_blockchain` and
4074
4169
  * `assigned_at` reconciling mixed states.
4075
- * Defaults to the public chain when nothing else resolves.
4170
+ * A lookup that names exactly one chain wins outright. Where it names
4171
+ * neither (a brand-new org) or cannot choose between them, the client's
4172
+ * configured default decides.
4076
4173
  */
4077
4174
  async resolveChainForOrg(orgName) {
4078
4175
  const name2 = orgName.trim();
4176
+ if (this._explicitChain) return this._defaultChain;
4177
+ const forced = this.forcedNetwork();
4178
+ if (forced) return chainForNetwork(forced);
4079
4179
  const cached = this._chainCache.get(name2);
4080
4180
  if (cached) return cached;
4081
4181
  const mapNetwork = await this.getActiveNetworkForOrg(name2);
@@ -4107,7 +4207,7 @@ var Atbash = class _Atbash {
4107
4207
  return PRIVATE_CHAIN;
4108
4208
  }
4109
4209
  if (pubSub && privSub) {
4110
- const chain = privSub.assigned_at > pubSub.assigned_at ? PRIVATE_CHAIN : PUBLIC_CHAIN;
4210
+ const chain = privSub.assigned_at === pubSub.assigned_at ? this._defaultChain : privSub.assigned_at > pubSub.assigned_at ? PRIVATE_CHAIN : PUBLIC_CHAIN;
4111
4211
  this._chainCache.set(orgName, chain);
4112
4212
  return chain;
4113
4213
  }
@@ -4128,8 +4228,8 @@ var Atbash = class _Atbash {
4128
4228
  this.endpoint
4129
4229
  );
4130
4230
  }
4131
- this._chainCache.set(orgName, PUBLIC_CHAIN);
4132
- return PUBLIC_CHAIN;
4231
+ this._chainCache.set(orgName, this._defaultChain);
4232
+ return this._defaultChain;
4133
4233
  }
4134
4234
  /** Drop any cached chain resolutions. Useful in tests. */
4135
4235
  clearChainCache() {
@@ -4180,6 +4280,7 @@ var Atbash = class _Atbash {
4180
4280
  async resolveAgentLookupNetwork(options) {
4181
4281
  if (options.chainOpts?.network) return options.chainOpts.network;
4182
4282
  if (options.chainOpts?.blockchainRid) return void 0;
4283
+ if (this._explicitChain) return this._defaultChain.network;
4183
4284
  const orgName = options.orgName ?? this.orgName;
4184
4285
  if (!orgName) return void 0;
4185
4286
  return (await this.resolveChainForOrg(orgName)).network;
@@ -4255,6 +4356,30 @@ var Atbash = class _Atbash {
4255
4356
  return void 0;
4256
4357
  }
4257
4358
  }
4359
+ /**
4360
+ * BRID for the client's configured default org, if it has one.
4361
+ *
4362
+ * Calls that carry no `orgName` argument are not chain-less: they still
4363
+ * belong to `this.orgName`, and that org lives on exactly one chain. Routing
4364
+ * them by the constructor's chain instead means a client configured
4365
+ * `network: "private"` reads the private chain for an org that lives on
4366
+ * public, and gets an empty answer rather than an error. So where an org is
4367
+ * known the org decides the chain, and the constructor's chain is what is
4368
+ * left when no org is known at all — the order `resolveAgentLookupNetwork`
4369
+ * already applies to agent metadata reads, and the order the dashboard
4370
+ * applies in `resolveChainForWallet`.
4371
+ *
4372
+ * Undefined when there is no default org, so callers keep falling back to
4373
+ * the client default.
4374
+ */
4375
+ /** The switch's chain, unless this client named one of its own. */
4376
+ forcedNetwork() {
4377
+ return this._explicitChain ? void 0 : this._forcedNetwork;
4378
+ }
4379
+ async defaultOrgBrid() {
4380
+ if (this._explicitChain || !this.orgName) return void 0;
4381
+ return this.bridForOrg(this.orgName);
4382
+ }
4258
4383
  async raiseIfError(resp) {
4259
4384
  if (resp.ok) return;
4260
4385
  throw await this.httpError(resp);
@@ -43504,10 +43629,13 @@ export {
43504
43629
  KEY_FILENAMES,
43505
43630
  MemoryGuardManager,
43506
43631
  MemoryIntegrityError,
43632
+ PRIVATE_CHAIN,
43633
+ PUBLIC_CHAIN,
43507
43634
  PointerStore,
43508
43635
  SignatureVerificationError,
43509
43636
  bootSyncFailureLine,
43510
43637
  buildAllowedJudgeHosts,
43638
+ chainForNetwork,
43511
43639
  chooseKeyPath,
43512
43640
  claimHashHex,
43513
43641
  classifyMemoryRead,