@hasna/domains 0.0.46 → 0.0.47

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/mcp/index.js CHANGED
@@ -5228,7 +5228,7 @@ var require_client = __commonJS((exports) => {
5228
5228
  };
5229
5229
  };
5230
5230
  var sleep = (seconds) => {
5231
- return new Promise((resolve3) => setTimeout(resolve3, seconds * 1000));
5231
+ return new Promise((resolve4) => setTimeout(resolve4, seconds * 1000));
5232
5232
  };
5233
5233
  var waiterServiceDefaults = {
5234
5234
  minDelay: 2,
@@ -5357,8 +5357,8 @@ var require_client = __commonJS((exports) => {
5357
5357
  };
5358
5358
  var abortTimeout = (abortSignal) => {
5359
5359
  let onAbort;
5360
- const promise = new Promise((resolve3) => {
5361
- onAbort = () => resolve3({ state: WaiterState.ABORTED });
5360
+ const promise = new Promise((resolve4) => {
5361
+ onAbort = () => resolve4({ state: WaiterState.ABORTED });
5362
5362
  if (typeof abortSignal.addEventListener === "function") {
5363
5363
  abortSignal.addEventListener("abort", onAbort);
5364
5364
  } else {
@@ -6011,8 +6011,8 @@ var require_client = __commonJS((exports) => {
6011
6011
 
6012
6012
  // ../../node_modules/.bun/@smithy+core@3.33.2/node_modules/@smithy/core/dist-cjs/submodules/config/index.js
6013
6013
  var require_config = __commonJS((exports) => {
6014
- var { homedir: homedir2 } = __require("os");
6015
- var { sep, join: join3 } = __require("path");
6014
+ var { homedir: homedir4 } = __require("os");
6015
+ var { sep, join: join5 } = __require("path");
6016
6016
  var { createHash: createHash2 } = __require("crypto");
6017
6017
  var { readFile: readFile$1 } = __require("fs/promises");
6018
6018
  var { IniSectionType } = require_dist_cjs();
@@ -6161,7 +6161,7 @@ var require_config = __commonJS((exports) => {
6161
6161
  return `${HOMEDRIVE}${HOMEPATH}`;
6162
6162
  const homeDirCacheKey = getHomeDirCacheKey();
6163
6163
  if (!homeDirCache[homeDirCacheKey])
6164
- homeDirCache[homeDirCacheKey] = homedir2();
6164
+ homeDirCache[homeDirCacheKey] = homedir4();
6165
6165
  return homeDirCache[homeDirCacheKey];
6166
6166
  };
6167
6167
  var ENV_PROFILE = "AWS_PROFILE";
@@ -6170,7 +6170,7 @@ var require_config = __commonJS((exports) => {
6170
6170
  var getSSOTokenFilepath = (id) => {
6171
6171
  const hasher = createHash2("sha1");
6172
6172
  const cacheName = hasher.update(id).digest("hex");
6173
- return join3(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
6173
+ return join5(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
6174
6174
  };
6175
6175
  var tokenIntercept = {};
6176
6176
  var getSSOTokenFromFile = async (id) => {
@@ -6197,9 +6197,9 @@ var require_config = __commonJS((exports) => {
6197
6197
  ...data.default && { default: data.default }
6198
6198
  });
6199
6199
  var ENV_CONFIG_PATH = "AWS_CONFIG_FILE";
6200
- var getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || join3(getHomeDir(), ".aws", "config");
6200
+ var getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || join5(getHomeDir(), ".aws", "config");
6201
6201
  var ENV_CREDENTIALS_PATH = "AWS_SHARED_CREDENTIALS_FILE";
6202
- var getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || join3(getHomeDir(), ".aws", "credentials");
6202
+ var getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || join5(getHomeDir(), ".aws", "credentials");
6203
6203
  var prefixKeyRegex = /^([\w-]+)\s(["'])?([\w-@+.%:/]+)\2$/;
6204
6204
  var profileNameBlockList = ["__proto__", "profile __proto__"];
6205
6205
  var parseIni = (iniData) => {
@@ -6265,11 +6265,11 @@ var require_config = __commonJS((exports) => {
6265
6265
  const relativeHomeDirPrefix = "~/";
6266
6266
  let resolvedFilepath = filepath;
6267
6267
  if (filepath.startsWith(relativeHomeDirPrefix)) {
6268
- resolvedFilepath = join3(homeDir2, filepath.slice(2));
6268
+ resolvedFilepath = join5(homeDir2, filepath.slice(2));
6269
6269
  }
6270
6270
  let resolvedConfigFilepath = configFilepath;
6271
6271
  if (configFilepath.startsWith(relativeHomeDirPrefix)) {
6272
- resolvedConfigFilepath = join3(homeDir2, configFilepath.slice(2));
6272
+ resolvedConfigFilepath = join5(homeDir2, configFilepath.slice(2));
6273
6273
  }
6274
6274
  const parsedFiles = await Promise.all([
6275
6275
  readFile(resolvedConfigFilepath, {
@@ -6486,7 +6486,7 @@ var require_config = __commonJS((exports) => {
6486
6486
  };
6487
6487
  var imdsRequest = async (options) => {
6488
6488
  const { request } = __require("http");
6489
- return new Promise((resolve3, reject) => {
6489
+ return new Promise((resolve4, reject) => {
6490
6490
  const req = request({
6491
6491
  hostname: options.hostname,
6492
6492
  port: options.port,
@@ -6514,7 +6514,7 @@ var require_config = __commonJS((exports) => {
6514
6514
  const chunks = [];
6515
6515
  res.on("data", (chunk) => chunks.push(chunk));
6516
6516
  res.on("end", () => {
6517
- resolve3(Buffer.concat(chunks));
6517
+ resolve4(Buffer.concat(chunks));
6518
6518
  req.destroy();
6519
6519
  });
6520
6520
  });
@@ -8865,7 +8865,7 @@ ${value}\r
8865
8865
  if (isReadableStream(stream)) {
8866
8866
  return headStream$1(stream, bytes);
8867
8867
  }
8868
- return new Promise((resolve3, reject) => {
8868
+ return new Promise((resolve4, reject) => {
8869
8869
  const collector = new Collector$1;
8870
8870
  collector.limit = bytes;
8871
8871
  stream.pipe(collector);
@@ -8876,7 +8876,7 @@ ${value}\r
8876
8876
  collector.on("error", reject);
8877
8877
  collector.on("finish", function() {
8878
8878
  const bytes2 = concatBytes(this.buffers);
8879
- resolve3(bytes2);
8879
+ resolve4(bytes2);
8880
8880
  });
8881
8881
  });
8882
8882
  };
@@ -8990,7 +8990,7 @@ ${value}\r
8990
8990
  if (isReadableStream(stream)) {
8991
8991
  return collectReadableStream(stream);
8992
8992
  }
8993
- return new Promise((resolve3, reject) => {
8993
+ return new Promise((resolve4, reject) => {
8994
8994
  const collector = new Collector;
8995
8995
  const nodeStream = stream;
8996
8996
  nodeStream.pipe(collector);
@@ -9001,7 +9001,7 @@ ${value}\r
9001
9001
  collector.on("error", reject);
9002
9002
  collector.on("finish", function() {
9003
9003
  const bytes = concatBytes(this.bufferedBytes);
9004
- resolve3(bytes);
9004
+ resolve4(bytes);
9005
9005
  });
9006
9006
  });
9007
9007
  };
@@ -9193,7 +9193,7 @@ var require_checksum = __commonJS((exports) => {
9193
9193
  callback();
9194
9194
  }
9195
9195
  }
9196
- var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve3, reject) => {
9196
+ var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve4, reject) => {
9197
9197
  if (!isReadStream(fileStream)) {
9198
9198
  reject(new Error("Unable to calculate hash for non-file streams."));
9199
9199
  return;
@@ -9211,7 +9211,7 @@ var require_checksum = __commonJS((exports) => {
9211
9211
  });
9212
9212
  hashCalculator.on("error", reject);
9213
9213
  hashCalculator.on("finish", function() {
9214
- hash.digest().then(resolve3).catch(reject);
9214
+ hash.digest().then(resolve4).catch(reject);
9215
9215
  });
9216
9216
  });
9217
9217
  var isReadStream = (stream) => typeof stream.path === "string";
@@ -9222,14 +9222,14 @@ var require_checksum = __commonJS((exports) => {
9222
9222
  const hash = new hashCtor;
9223
9223
  const hashCalculator = new HashCalculator(hash);
9224
9224
  readableStream.pipe(hashCalculator);
9225
- return new Promise((resolve3, reject) => {
9225
+ return new Promise((resolve4, reject) => {
9226
9226
  readableStream.on("error", (err) => {
9227
9227
  hashCalculator.end();
9228
9228
  reject(err);
9229
9229
  });
9230
9230
  hashCalculator.on("error", reject);
9231
9231
  hashCalculator.on("finish", () => {
9232
- hash.digest().then(resolve3).catch(reject);
9232
+ hash.digest().then(resolve4).catch(reject);
9233
9233
  });
9234
9234
  });
9235
9235
  };
@@ -10335,7 +10335,7 @@ var require_event_streams = __commonJS((exports) => {
10335
10335
  streamEnded = true;
10336
10336
  });
10337
10337
  while (!generationEnded) {
10338
- const value = await new Promise((resolve3) => setTimeout(() => resolve3(records.shift()), 0));
10338
+ const value = await new Promise((resolve4) => setTimeout(() => resolve4(records.shift()), 0));
10339
10339
  if (value) {
10340
10340
  yield value;
10341
10341
  }
@@ -11215,8 +11215,8 @@ var require_protocols = __commonJS((exports) => {
11215
11215
  async build() {
11216
11216
  const { hostname, protocol = "https", port, path: basePath } = await this.context.endpoint();
11217
11217
  this.path = basePath;
11218
- for (const resolvePath of this.resolvePathStack) {
11219
- resolvePath(this.path);
11218
+ for (const resolvePath2 of this.resolvePathStack) {
11219
+ resolvePath2(this.path);
11220
11220
  }
11221
11221
  return new HttpRequest({
11222
11222
  protocol,
@@ -11830,7 +11830,7 @@ var require_retry = __commonJS((exports) => {
11830
11830
  }
11831
11831
  };
11832
11832
  }
11833
- var cooldown = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
11833
+ var cooldown = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
11834
11834
  var isRetryStrategyV2 = (retryStrategy) => typeof retryStrategy.acquireInitialRetryToken !== "undefined" && typeof retryStrategy.refreshRetryTokenForRetry !== "undefined" && typeof retryStrategy.recordSuccess !== "undefined";
11835
11835
  var getRetryErrorInfo = (error, logger) => {
11836
11836
  const errorInfo = {
@@ -11929,7 +11929,7 @@ var require_retry = __commonJS((exports) => {
11929
11929
  this.refillTokenBucket();
11930
11930
  while (amount > this.availableTokens) {
11931
11931
  const delay = (amount - this.availableTokens) / this.fillRate * 1000;
11932
- await new Promise((resolve3) => DefaultRateLimiter.setTimeoutFn(resolve3, delay));
11932
+ await new Promise((resolve4) => DefaultRateLimiter.setTimeoutFn(resolve4, delay));
11933
11933
  this.refillTokenBucket();
11934
11934
  }
11935
11935
  this.availableTokens = this.availableTokens - amount;
@@ -12271,7 +12271,7 @@ var require_retry = __commonJS((exports) => {
12271
12271
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
12272
12272
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
12273
12273
  totalDelay += delay;
12274
- await new Promise((resolve3) => setTimeout(resolve3, delay));
12274
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
12275
12275
  continue;
12276
12276
  }
12277
12277
  if (!err.$metadata) {
@@ -15604,7 +15604,7 @@ var init_node_http = () => {};
15604
15604
 
15605
15605
  // ../../node_modules/.bun/@smithy+credential-provider-imds@4.5.2/node_modules/@smithy/credential-provider-imds/dist-es/remoteProvider/httpRequest.js
15606
15606
  function httpRequest(options) {
15607
- return new Promise((resolve3, reject) => {
15607
+ return new Promise((resolve4, reject) => {
15608
15608
  const req = node_http.request({
15609
15609
  method: "GET",
15610
15610
  ...options,
@@ -15629,7 +15629,7 @@ function httpRequest(options) {
15629
15629
  chunks.push(chunk);
15630
15630
  });
15631
15631
  res.on("end", () => {
15632
- resolve3(Buffer.concat(chunks));
15632
+ resolve4(Buffer.concat(chunks));
15633
15633
  req.destroy();
15634
15634
  });
15635
15635
  });
@@ -15853,9 +15853,9 @@ var import_config6, IMDS_PATH = "/latest/meta-data/iam/security-credentials/", I
15853
15853
  let fallbackBlockedFromProcessEnv = false;
15854
15854
  const configValue = await import_config6.loadConfig({
15855
15855
  environmentVariableSelector: (env) => {
15856
- const envValue = env[AWS_EC2_METADATA_V1_DISABLED];
15857
- fallbackBlockedFromProcessEnv = !!envValue && envValue !== "false";
15858
- if (envValue === undefined) {
15856
+ const envValue2 = env[AWS_EC2_METADATA_V1_DISABLED];
15857
+ fallbackBlockedFromProcessEnv = !!envValue2 && envValue2 !== "false";
15858
+ if (envValue2 === undefined) {
15859
15859
  throw new import_config6.CredentialsProviderError(`${AWS_EC2_METADATA_V1_DISABLED} not set in env, checking config file next.`, { logger: init.logger });
15860
15860
  }
15861
15861
  return fallbackBlockedFromProcessEnv;
@@ -16123,21 +16123,21 @@ var require_dist_cjs4 = __commonJS((exports) => {
16123
16123
  let sendBody = true;
16124
16124
  if (!externalAgent && expect === "100-continue") {
16125
16125
  sendBody = await Promise.race([
16126
- new Promise((resolve3) => {
16127
- timeoutId = Number(timing.setTimeout(() => resolve3(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
16126
+ new Promise((resolve4) => {
16127
+ timeoutId = Number(timing.setTimeout(() => resolve4(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
16128
16128
  }),
16129
- new Promise((resolve3) => {
16129
+ new Promise((resolve4) => {
16130
16130
  httpRequest2.on("continue", () => {
16131
16131
  timing.clearTimeout(timeoutId);
16132
- resolve3(true);
16132
+ resolve4(true);
16133
16133
  });
16134
16134
  httpRequest2.on("response", () => {
16135
16135
  timing.clearTimeout(timeoutId);
16136
- resolve3(false);
16136
+ resolve4(false);
16137
16137
  });
16138
16138
  httpRequest2.on("error", () => {
16139
16139
  timing.clearTimeout(timeoutId);
16140
- resolve3(false);
16140
+ resolve4(false);
16141
16141
  });
16142
16142
  })
16143
16143
  ]);
@@ -16212,13 +16212,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
16212
16212
  return socketWarningTimestamp;
16213
16213
  }
16214
16214
  constructor(options) {
16215
- this.configProvider = new Promise((resolve3, reject) => {
16215
+ this.configProvider = new Promise((resolve4, reject) => {
16216
16216
  if (typeof options === "function") {
16217
16217
  options().then((_options) => {
16218
- resolve3(this.resolveDefaultConfig(_options));
16218
+ resolve4(this.resolveDefaultConfig(_options));
16219
16219
  }).catch(reject);
16220
16220
  } else {
16221
- resolve3(this.resolveDefaultConfig(options));
16221
+ resolve4(this.resolveDefaultConfig(options));
16222
16222
  }
16223
16223
  });
16224
16224
  }
@@ -16250,7 +16250,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
16250
16250
  timing.clearTimeout(socketTimeoutId);
16251
16251
  timing.clearTimeout(keepAliveTimeoutId);
16252
16252
  };
16253
- const resolve3 = async (arg) => {
16253
+ const resolve4 = async (arg) => {
16254
16254
  await writeRequestBodyPromise;
16255
16255
  clearTimeouts();
16256
16256
  _resolve(arg);
@@ -16314,7 +16314,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
16314
16314
  headers: getTransformedHeaders(res.headers),
16315
16315
  body: res
16316
16316
  });
16317
- resolve3({ response: httpResponse });
16317
+ resolve4({ response: httpResponse });
16318
16318
  });
16319
16319
  req.on("error", (err) => {
16320
16320
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -16646,13 +16646,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
16646
16646
  return new NodeHttp2Handler(instanceOrOptions);
16647
16647
  }
16648
16648
  constructor(options) {
16649
- this.configProvider = new Promise((resolve3, reject) => {
16649
+ this.configProvider = new Promise((resolve4, reject) => {
16650
16650
  if (typeof options === "function") {
16651
16651
  options().then((opts) => {
16652
- resolve3(opts || {});
16652
+ resolve4(opts || {});
16653
16653
  }).catch(reject);
16654
16654
  } else {
16655
- resolve3(options || {});
16655
+ resolve4(options || {});
16656
16656
  }
16657
16657
  });
16658
16658
  }
@@ -16677,7 +16677,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
16677
16677
  return new Promise((_resolve, _reject) => {
16678
16678
  let fulfilled = false;
16679
16679
  let writeRequestBodyPromise = undefined;
16680
- const resolve3 = async (arg) => {
16680
+ const resolve4 = async (arg) => {
16681
16681
  await writeRequestBodyPromise;
16682
16682
  _resolve(arg);
16683
16683
  };
@@ -16762,7 +16762,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
16762
16762
  body: clientHttp2Stream
16763
16763
  });
16764
16764
  fulfilled = true;
16765
- resolve3({ response: httpResponse });
16765
+ resolve4({ response: httpResponse });
16766
16766
  if (useIsolatedSession) {
16767
16767
  session.close();
16768
16768
  }
@@ -16888,7 +16888,7 @@ var retryWrapper = (toRetry, maxRetries, delayMs) => {
16888
16888
  try {
16889
16889
  return await toRetry();
16890
16890
  } catch (e) {
16891
- await new Promise((resolve3) => setTimeout(resolve3, delayMs));
16891
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
16892
16892
  }
16893
16893
  }
16894
16894
  return await toRetry();
@@ -26096,8 +26096,8 @@ var require_signin = __commonJS((exports) => {
26096
26096
  // ../../node_modules/.bun/@aws-sdk+credential-provider-login@3.972.76/node_modules/@aws-sdk/credential-provider-login/dist-es/LoginCredentialsFetcher.js
26097
26097
  import { createHash as createHash2, createPrivateKey, createPublicKey, sign } from "crypto";
26098
26098
  import { promises as fs2 } from "fs";
26099
- import { homedir as homedir2 } from "os";
26100
- import { dirname as dirname3, join as join3 } from "path";
26099
+ import { homedir as homedir4 } from "os";
26100
+ import { dirname as dirname3, join as join5 } from "path";
26101
26101
  var import_config20, import_protocols3, LoginCredentialsFetcher;
26102
26102
  var init_LoginCredentialsFetcher = __esm(() => {
26103
26103
  import_config20 = __toESM(require_config(), 1);
@@ -26264,10 +26264,10 @@ var init_LoginCredentialsFetcher = __esm(() => {
26264
26264
  await fs2.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
26265
26265
  }
26266
26266
  getTokenFilePath() {
26267
- const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join3(homedir2(), ".aws", "login", "cache");
26267
+ const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join5(homedir4(), ".aws", "login", "cache");
26268
26268
  const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
26269
26269
  const loginSessionSha256 = createHash2("sha256").update(loginSessionBytes).digest("hex");
26270
- return join3(directory, `${loginSessionSha256}.json`);
26270
+ return join5(directory, `${loginSessionSha256}.json`);
26271
26271
  }
26272
26272
  derToRawSignature(derSignature) {
26273
26273
  let offset = 2;
@@ -26841,9 +26841,9 @@ async function startMcpHttpServer(buildServer, options) {
26841
26841
  res.writeHead(404, { "Content-Type": "text/plain" });
26842
26842
  res.end("Not Found");
26843
26843
  });
26844
- await new Promise((resolve3, reject) => {
26844
+ await new Promise((resolve4, reject) => {
26845
26845
  httpServer.once("error", reject);
26846
- httpServer.listen(requestedPort, host, () => resolve3());
26846
+ httpServer.listen(requestedPort, host, () => resolve4());
26847
26847
  });
26848
26848
  const addr = httpServer.address();
26849
26849
  const port = typeof addr === "object" && addr ? addr.port : requestedPort;
@@ -26851,8 +26851,8 @@ async function startMcpHttpServer(buildServer, options) {
26851
26851
  return {
26852
26852
  port,
26853
26853
  host,
26854
- close: () => new Promise((resolve3, reject) => {
26855
- httpServer.close((err) => err ? reject(err) : resolve3());
26854
+ close: () => new Promise((resolve4, reject) => {
26855
+ httpServer.close((err) => err ? reject(err) : resolve4());
26856
26856
  })
26857
26857
  };
26858
26858
  }
@@ -26996,6 +26996,7 @@ import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprot
26996
26996
  // ../contracts/dist/client/storage.js
26997
26997
  import { isIP } from "net";
26998
26998
  import { readFileSync, statSync } from "fs";
26999
+ import { createRequire } from "module";
26999
27000
  import { join } from "path";
27000
27001
  function envToken(name) {
27001
27002
  return name.toUpperCase().replace(/-/g, "_");
@@ -27011,6 +27012,9 @@ function credentialOverrideEnvKey(name) {
27011
27012
  return `HASNA_${envToken(name)}_API_KEY_OVERRIDE`;
27012
27013
  }
27013
27014
  var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE";
27015
+ function credentialPointerEnvKey(name) {
27016
+ return `HASNA_${envToken(name)}_API_KEY_REF`;
27017
+ }
27014
27018
 
27015
27019
  class CredentialResolutionError extends Error {
27016
27020
  appName;
@@ -27023,31 +27027,55 @@ class CredentialResolutionError extends Error {
27023
27027
  }
27024
27028
  }
27025
27029
  var HASNA_STATE_DIR = ".hasna";
27026
- var FLEET_CREDENTIAL_DIR = "cloud";
27030
+ var FLEET_CREDENTIAL_DIR = "fleet-env";
27031
+ var LEGACY_CLOUD_DIR = "cloud";
27027
27032
  var CONFIG_DIR = ".config";
27028
27033
  var CONFIG_NAMESPACE = "hasna";
27034
+ var LEGACY_CLOUD_REMOVAL_DEADLINE = "2026-10-01";
27029
27035
  var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
27030
27036
  var SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
27031
27037
  var SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
27032
27038
  var ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
27039
+ var VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
27033
27040
  function homeDir(env) {
27034
27041
  const home = env.HOME?.trim();
27035
27042
  return home ? home : null;
27036
27043
  }
27037
- function credentialDiskSources(name, env) {
27038
- return profileDiskSources(name, env, null);
27039
- }
27040
- function profileDiskSources(name, env, profile) {
27044
+ function credentialDiskSourceList(name, env, profile = null) {
27041
27045
  const home = homeDir(env);
27042
27046
  if (!home || !SAFE_APP_SLUG.test(name))
27043
27047
  return [];
27044
27048
  const stem = profile ? `${name}.${profile}` : name;
27045
27049
  const configStem = profile ? `${name}-${profile}` : name;
27046
27050
  return [
27047
- join(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
27048
- join(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`)
27051
+ {
27052
+ path: join(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
27053
+ tier: "fleet-env",
27054
+ deprecated: false
27055
+ },
27056
+ {
27057
+ path: join(home, HASNA_STATE_DIR, LEGACY_CLOUD_DIR, `${stem}.env`),
27058
+ tier: "legacy-cloud",
27059
+ deprecated: true
27060
+ },
27061
+ {
27062
+ path: join(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}.env`),
27063
+ tier: "config",
27064
+ deprecated: false
27065
+ },
27066
+ {
27067
+ path: join(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`),
27068
+ tier: "config-legacy",
27069
+ deprecated: true
27070
+ }
27049
27071
  ];
27050
27072
  }
27073
+ function credentialDiskSources(name, env) {
27074
+ return credentialDiskSourceList(name, env, null).map((s) => s.path);
27075
+ }
27076
+ function profileDiskSources(name, env, profile) {
27077
+ return credentialDiskSourceList(name, env, profile).map((s) => s.path);
27078
+ }
27051
27079
  function parseEnvFile(text) {
27052
27080
  const values = new Map;
27053
27081
  for (const rawLine of text.split(/\r?\n/)) {
@@ -27115,6 +27143,9 @@ function appConfigDiskValue(name, env, keys) {
27115
27143
  return null;
27116
27144
  }
27117
27145
  function assertUsableCredential(appName, source, value) {
27146
+ if (VAULT_POINTER_SHAPE.test(value)) {
27147
+ throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
27148
+ }
27118
27149
  if (!ILLEGAL_IN_HEADER_VALUE.test(value))
27119
27150
  return;
27120
27151
  throw new CredentialResolutionError(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
@@ -27139,6 +27170,14 @@ function sealCredential(fields) {
27139
27170
  writable: false,
27140
27171
  configurable: false
27141
27172
  });
27173
+ if (fields.pointerVaultKey !== undefined) {
27174
+ Object.defineProperty(sealed, "pointerVaultKey", {
27175
+ value: fields.pointerVaultKey,
27176
+ enumerable: false,
27177
+ writable: false,
27178
+ configurable: false
27179
+ });
27180
+ }
27142
27181
  Object.defineProperty(sealed, INSPECT_CUSTOM, {
27143
27182
  value: () => ({ ...visible, apiKey: "[redacted]" }),
27144
27183
  enumerable: false,
@@ -27190,7 +27229,8 @@ function validateAndSealResolvedCredential(appName, credential) {
27190
27229
  deliberate: credential.deliberate,
27191
27230
  deprecated: credential.deprecated,
27192
27231
  diskCandidates: credential.diskCandidates,
27193
- warning: credential.warning
27232
+ warning: credential.warning,
27233
+ ...credential.pointerVaultKey !== undefined ? { pointerVaultKey: credential.pointerVaultKey } : {}
27194
27234
  });
27195
27235
  }
27196
27236
  function firstEnvValue(env, keys) {
@@ -27251,6 +27291,27 @@ function resolveCredential(name, env, options = {}) {
27251
27291
  warning: null
27252
27292
  });
27253
27293
  }
27294
+ const pointerKeyName = credentialPointerEnvKey(name);
27295
+ const pointerRaw = env[pointerKeyName];
27296
+ if (pointerRaw !== undefined) {
27297
+ const pointer = pointerRaw.trim();
27298
+ if (!pointer) {
27299
+ throw new CredentialResolutionError(name, `${pointerKeyName} is set but empty. It is a deliberate vault pointer, so it is not resolved around: ` + `either give it a vault item key or unset it to fall back to the credential on disk.`, [pointerKeyName]);
27300
+ }
27301
+ if (!VAULT_POINTER_SHAPE.test(pointer)) {
27302
+ throw new CredentialResolutionError(name, `${pointerKeyName} must name a vault ITEM KEY (a path-shaped reference like ` + `'namespace/app/live/api_key'), not a credential value. A pointer that carries a literal is refused.`, [pointerKeyName]);
27303
+ }
27304
+ return sealCredential({
27305
+ apiKey: "",
27306
+ pointerVaultKey: pointer,
27307
+ tier: "pointer",
27308
+ source: pointerKeyName,
27309
+ deliberate: true,
27310
+ deprecated: false,
27311
+ diskCandidates: diskPaths,
27312
+ warning: null
27313
+ });
27314
+ }
27254
27315
  const profile = options.profile?.trim() || env[CREDENTIAL_PROFILE_ENV_KEY]?.trim();
27255
27316
  if (profile) {
27256
27317
  const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
@@ -27275,26 +27336,42 @@ function resolveCredential(name, env, options = {}) {
27275
27336
  }
27276
27337
  throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY}.`, paths);
27277
27338
  }
27278
- const diskHits = diskPaths.map((path) => ({ path, value: readCredentialFile(path, apiKeyKeys) })).filter((hit) => hit.value !== null);
27339
+ const diskSourceList = credentialDiskSourceList(name, env, null);
27340
+ const diskHits = diskSourceList.map((src) => ({ src, value: readCredentialFile(src.path, apiKeyKeys) })).filter((hit) => hit.value !== null);
27279
27341
  if (diskHits.length > 0) {
27280
27342
  const winner = diskHits[0];
27281
- assertUsableCredential(name, winner.path, winner.value);
27343
+ assertUsableCredential(name, winner.src.path, winner.value);
27282
27344
  const divergentSources = [
27283
- ...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.path),
27345
+ ...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.src.path),
27284
27346
  ...(() => {
27285
27347
  const legacyHit = firstEnvValue(env, apiKeyKeys);
27286
27348
  return legacyHit && legacyHit.value !== winner.value ? [legacyHit.key] : [];
27287
27349
  })()
27288
27350
  ];
27289
- const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
27351
+ const warning = divergentSources.length > 0 ? `Credential sources disagree for '${name}': ${winner.src.path} and ` + `${divergentSources.join(", ")} hold different keys. ${winner.src.path} wins, because a file on ` + `disk is re-read on every call while an environment variable is a snapshot. Reconcile them \u2014 ` + `a rotation that updated only one leaves the other to fail 401 wherever it is loaded first.` : null;
27352
+ let deprecated = winner.src.deprecated;
27353
+ let finalWarning = warning;
27354
+ if (winner.src.deprecated) {
27355
+ deprecated = true;
27356
+ const sink = options.onDeprecation ?? defaultDeprecationSink;
27357
+ const notified = deprecationNotified();
27358
+ const noticeKey = `${name}:${winner.src.path}`;
27359
+ if (!notified.has(noticeKey)) {
27360
+ notified.add(noticeKey);
27361
+ const target = diskSourceList[0]?.path ?? "<none>";
27362
+ const message = `[${name}] DEPRECATED: the API key came from ${winner.src.path} \u2014 a legacy credential location. ` + `The primary location is ${target} (~/.hasna/fleet-env/<app>.env). The legacy 'cloud' tiers are ` + `removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}. Migrate the key to the primary location.`;
27363
+ sink(message);
27364
+ }
27365
+ finalWarning = [warning, `Legacy credential source: ${winner.src.path}. Removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}.`].filter(Boolean).join(" ") || null;
27366
+ }
27290
27367
  return sealCredential({
27291
27368
  apiKey: winner.value,
27292
- tier: "disk",
27293
- source: winner.path,
27369
+ tier: winner.src.tier,
27370
+ source: winner.src.path,
27294
27371
  deliberate: false,
27295
- deprecated: false,
27372
+ deprecated,
27296
27373
  diskCandidates: diskPaths,
27297
- warning
27374
+ warning: finalWarning
27298
27375
  });
27299
27376
  }
27300
27377
  const legacy = firstEnvValue(env, apiKeyKeys);
@@ -27320,6 +27397,47 @@ function resolveCredential(name, env, options = {}) {
27320
27397
  }
27321
27398
  return null;
27322
27399
  }
27400
+ var SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
27401
+ var requireSecretsSdk = createRequire(import.meta.url);
27402
+ async function completePointerCredential(name, pointerResolution, env = process.env) {
27403
+ const vaultKey = pointerResolution.pointerVaultKey;
27404
+ const pointerEnvKey = pointerResolution.source;
27405
+ if (!vaultKey) {
27406
+ throw new CredentialResolutionError(name, `Pointer resolution from ${pointerEnvKey} carries no vault item key; this is a defect in the resolver.`, [pointerEnvKey]);
27407
+ }
27408
+ let secretsSdk;
27409
+ try {
27410
+ secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
27411
+ } catch {
27412
+ throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
27413
+ }
27414
+ let client;
27415
+ try {
27416
+ client = secretsSdk.createSecretsClientFromEnv(env);
27417
+ } catch {
27418
+ throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets client could not be configured from this ` + `environment (the secrets service URL and key env are missing or invalid). A vault pointer is TERMINAL and ` + `never falls through to a literal or disk credential.`, [pointerEnvKey]);
27419
+ }
27420
+ let secret;
27421
+ try {
27422
+ secret = await client.getSecret({ key: vaultKey });
27423
+ } catch {
27424
+ throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the vault could not be reached or the item is ` + `unavailable. A vault pointer is TERMINAL and never falls through to a literal or disk credential.`, [pointerEnvKey]);
27425
+ }
27426
+ const value = secret.value;
27427
+ if (!value) {
27428
+ throw new CredentialResolutionError(name, `${pointerEnvKey} resolved vault item '${vaultKey}', but it holds no value. A vault pointer is TERMINAL.`, [pointerEnvKey]);
27429
+ }
27430
+ assertUsableCredential(name, `${pointerEnvKey} -> vault:${vaultKey}`, value);
27431
+ return sealCredential({
27432
+ apiKey: value,
27433
+ tier: "pointer",
27434
+ source: `${pointerEnvKey} -> vault:${vaultKey}`,
27435
+ deliberate: true,
27436
+ deprecated: false,
27437
+ diskCandidates: pointerResolution.diskCandidates,
27438
+ warning: null
27439
+ });
27440
+ }
27323
27441
  var ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
27324
27442
  var DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
27325
27443
  function isValidDnsDomain(value) {
@@ -27565,6 +27683,13 @@ function currentCredential(name, apiKey) {
27565
27683
  }
27566
27684
  return explicitCredential(name, apiKey);
27567
27685
  }
27686
+ async function resolveRequestCredential(name, apiKey, env = process.env) {
27687
+ const resolved = currentCredential(name, apiKey);
27688
+ if (resolved.tier === "pointer") {
27689
+ return completePointerCredential(name, resolved, env);
27690
+ }
27691
+ return resolved;
27692
+ }
27568
27693
  function authFailureGuidance(credential) {
27569
27694
  const origin = `The API key for this request came from ${credential.source}`;
27570
27695
  if (credential.deliberate) {
@@ -27720,7 +27845,7 @@ function createHasnaHttpTransport(options) {
27720
27845
  const retry = resolveRetry(opts.retry);
27721
27846
  const methodRetryable = IDEMPOTENT_METHODS.has(upper) || Boolean(opts.idempotencyKey);
27722
27847
  const maxAttempts = retry && methodRetryable ? retry.retries + 1 : 1;
27723
- const credential = currentCredential(options.name, options.apiKey);
27848
+ const credential = await resolveRequestCredential(options.name, options.apiKey);
27724
27849
  let last = null;
27725
27850
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
27726
27851
  const result = await once(upper, rel, url, body, opts, credential);
@@ -27885,6 +28010,7 @@ function resolveStorageClient(name, env = process.env, overrides) {
27885
28010
  }
27886
28011
 
27887
28012
  // ../contracts/dist/client/transport.js
28013
+ import { createRequire as createRequire2 } from "module";
27888
28014
  function envToken2(name) {
27889
28015
  return name.toUpperCase().replace(/-/g, "_");
27890
28016
  }
@@ -27899,6 +28025,8 @@ var MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
27899
28025
  var INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
27900
28026
  var CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
27901
28027
  var DEPRECATION_REGISTRY2 = Symbol.for("hasna:contracts:credentialDeprecationNotices");
28028
+ var SECRETS_PACKAGE_SPECIFIER2 = "@hasna/" + "secrets";
28029
+ var requireSecretsSdk2 = createRequire2(import.meta.url);
27902
28030
  var IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
27903
28031
  var AUTHORITY_OVERRIDE_HEADERS2 = new Set([
27904
28032
  "host",
@@ -27913,15 +28041,15 @@ import { Database } from "bun:sqlite";
27913
28041
  import { createHash } from "crypto";
27914
28042
  import {
27915
28043
  copyFileSync,
27916
- existsSync,
28044
+ existsSync as existsSync2,
27917
28045
  mkdirSync,
27918
28046
  readFileSync as readFileSync2,
27919
28047
  readdirSync,
27920
28048
  statSync as statSync2,
27921
28049
  writeFileSync
27922
28050
  } from "fs";
27923
- import { dirname, join as join2, resolve } from "path";
27924
- import { homedir } from "os";
28051
+ import { dirname, join as join4, resolve as resolve2 } from "path";
28052
+ import { homedir as homedir3 } from "os";
27925
28053
 
27926
28054
  // src/db/migrations.ts
27927
28055
  var MIGRATIONS = [
@@ -28190,10 +28318,116 @@ var MIGRATIONS = [
28190
28318
  }
28191
28319
  ];
28192
28320
 
28321
+ // src/lib/app-home.ts
28322
+ import { existsSync } from "fs";
28323
+ import { homedir as homedir2 } from "os";
28324
+ import { join as join3, resolve } from "path";
28325
+
28326
+ // ../../node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
28327
+ import { homedir } from "os";
28328
+ import { join as join2 } from "path";
28329
+ var KIND_ENV = {
28330
+ config: "HASNA_CONFIG_HOME",
28331
+ data: "HASNA_DATA_HOME",
28332
+ state: "HASNA_STATE_HOME",
28333
+ cache: "HASNA_CACHE_HOME"
28334
+ };
28335
+ var APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
28336
+ function assertApp(app) {
28337
+ if (typeof app !== "string" || app.length === 0) {
28338
+ throw new TypeError("paths: app must be a non-empty string");
28339
+ }
28340
+ if (!APP_SLUG_RE.test(app)) {
28341
+ throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
28342
+ }
28343
+ }
28344
+ function envOf(options) {
28345
+ return options.env ?? process.env;
28346
+ }
28347
+ function envValue(options, kind) {
28348
+ const value = envOf(options)[KIND_ENV[kind]];
28349
+ return typeof value === "string" && value.length > 0 ? value : undefined;
28350
+ }
28351
+ function isMacOS(platform) {
28352
+ return platform === "darwin";
28353
+ }
28354
+ function baseDir(kind, options) {
28355
+ const override = envValue(options, kind);
28356
+ if (override)
28357
+ return override;
28358
+ const home = options.home ?? homedir();
28359
+ const platform = options.platform ?? process.platform;
28360
+ if (isMacOS(platform)) {
28361
+ switch (kind) {
28362
+ case "config":
28363
+ case "data":
28364
+ return join2(home, "Library", "Application Support", "Hasna");
28365
+ case "cache":
28366
+ return join2(home, "Library", "Caches", "Hasna");
28367
+ case "state":
28368
+ return join2(home, "Library", "Logs", "Hasna");
28369
+ }
28370
+ }
28371
+ switch (kind) {
28372
+ case "config":
28373
+ return join2(home, ".config", "hasna");
28374
+ case "data":
28375
+ return join2(home, ".local", "share", "hasna");
28376
+ case "state":
28377
+ return join2(home, ".local", "state", "hasna");
28378
+ case "cache":
28379
+ return join2(home, ".cache", "hasna");
28380
+ }
28381
+ }
28382
+ function resolvePath(kind, options) {
28383
+ assertApp(options.app);
28384
+ const appSegment = options.internal === true ? join2("internal", options.app) : options.app;
28385
+ return join2(baseDir(kind, options), appSegment);
28386
+ }
28387
+ function dataDir(options) {
28388
+ return resolvePath("data", options);
28389
+ }
28390
+
28391
+ // src/lib/app-home.ts
28392
+ var APP = "domains";
28393
+ function effectiveHome(env = process.env) {
28394
+ return env["HOME"] || env["USERPROFILE"] || homedir2();
28395
+ }
28396
+ function legacyHomeDir(env = process.env) {
28397
+ return join3(effectiveHome(env), ".hasna", APP);
28398
+ }
28399
+ function resolverHome(env = process.env) {
28400
+ const home = env["HOME"] || env["USERPROFILE"];
28401
+ return dataDir({ app: APP, home, env });
28402
+ }
28403
+ function adoptResolverHome(resolved, env = process.env) {
28404
+ const dataOverride = env.HASNA_DATA_HOME;
28405
+ if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
28406
+ return true;
28407
+ return existsSync(join3(resolved, "domains.db"));
28408
+ }
28409
+ function exactAppOverride(env = process.env) {
28410
+ const override = env["HASNA_DOMAINS_HOME"] ?? env["DOMAINS_HOME"] ?? env["HASNA_DOMAINS_DIR"] ?? env["DOMAINS_DIR"];
28411
+ return override && override.trim() ? override.trim() : undefined;
28412
+ }
28413
+ function appHome(env = process.env) {
28414
+ const override = exactAppOverride(env);
28415
+ if (override)
28416
+ return resolve(override);
28417
+ const resolved = resolverHome(env);
28418
+ return adoptResolverHome(resolved, env) ? resolve(resolved) : resolve(legacyHomeDir(env));
28419
+ }
28420
+ function getDefaultDbPath(env = process.env) {
28421
+ return join3(appHome(env), `${APP}.db`);
28422
+ }
28423
+ function getDefaultConfigPath(env = process.env) {
28424
+ return join3(appHome(env), "config.json");
28425
+ }
28426
+
28193
28427
  // src/db/database.ts
28194
28428
  var _db = null;
28195
28429
  function canonicalHome(env) {
28196
- return env["HOME"] || env["USERPROFILE"] || homedir();
28430
+ return env["HOME"] || env["USERPROFILE"] || homedir3();
28197
28431
  }
28198
28432
  function sha256File(path) {
28199
28433
  return createHash("sha256").update(readFileSync2(path)).digest("hex");
@@ -28201,20 +28435,20 @@ function sha256File(path) {
28201
28435
  function migrateLegacyDataDir(env = process.env, dryRun = false) {
28202
28436
  const report = { dryRun, wouldCopy: [], copied: [] };
28203
28437
  const home = canonicalHome(env);
28204
- const xdgData = env["XDG_DATA_HOME"]?.trim() || join2(home, ".local", "share");
28205
- const oldDir = join2(xdgData, "open-domains");
28206
- const oldDb = join2(oldDir, "domains.db");
28207
- if (!existsSync(oldDb))
28438
+ const xdgData = env["XDG_DATA_HOME"]?.trim() || join4(home, ".local", "share");
28439
+ const oldDir = join4(xdgData, "open-domains");
28440
+ const oldDb = join4(oldDir, "domains.db");
28441
+ if (!existsSync2(oldDb))
28208
28442
  return report;
28209
- const canonicalDir = join2(home, ".hasna", "domains");
28210
- const newDb = join2(canonicalDir, "domains.db");
28211
- if (existsSync(newDb))
28443
+ const canonicalDir = join4(home, ".hasna", "domains");
28444
+ const newDb = join4(canonicalDir, "domains.db");
28445
+ if (existsSync2(newDb))
28212
28446
  return report;
28213
- if (existsSync(join2(canonicalDir, ".migrated-from-xdg.receipt.json")))
28447
+ if (existsSync2(join4(canonicalDir, ".migrated-from-xdg.receipt.json")))
28214
28448
  return report;
28215
28449
  if (dryRun) {
28216
28450
  for (const name of ["domains.db", "domains.db-wal", "domains.db-shm"]) {
28217
- if (existsSync(join2(oldDir, name)) && !existsSync(join2(canonicalDir, name))) {
28451
+ if (existsSync2(join4(oldDir, name)) && !existsSync2(join4(canonicalDir, name))) {
28218
28452
  report.wouldCopy.push(name);
28219
28453
  }
28220
28454
  }
@@ -28223,11 +28457,11 @@ function migrateLegacyDataDir(env = process.env, dryRun = false) {
28223
28457
  mkdirSync(canonicalDir, { recursive: true });
28224
28458
  const copied = [];
28225
28459
  for (const name of ["domains.db", "domains.db-wal", "domains.db-shm"]) {
28226
- const from = join2(oldDir, name);
28227
- if (!existsSync(from))
28460
+ const from = join4(oldDir, name);
28461
+ if (!existsSync2(from))
28228
28462
  continue;
28229
- const to = join2(canonicalDir, name);
28230
- if (existsSync(to))
28463
+ const to = join4(canonicalDir, name);
28464
+ if (existsSync2(to))
28231
28465
  continue;
28232
28466
  copyFileSync(from, to);
28233
28467
  copied.push({ name, bytes: statSync2(to).size, sha256: sha256File(to) });
@@ -28236,7 +28470,7 @@ function migrateLegacyDataDir(env = process.env, dryRun = false) {
28236
28470
  if (statSync2(newDb).size !== statSync2(oldDb).size || sha256File(newDb) !== sha256File(oldDb)) {
28237
28471
  throw new Error(`Refusing migration: copied ${newDb} does not byte-match ${oldDb}; the canonical root was not populated.`);
28238
28472
  }
28239
- writeFileSync(join2(canonicalDir, ".migrated-from-xdg.receipt.json"), `${JSON.stringify({
28473
+ writeFileSync(join4(canonicalDir, ".migrated-from-xdg.receipt.json"), `${JSON.stringify({
28240
28474
  migratedAt: new Date().toISOString(),
28241
28475
  from: oldDir,
28242
28476
  to: canonicalDir,
@@ -28250,26 +28484,26 @@ function getDbPath(env = process.env) {
28250
28484
  return env["DOMAINS_DB_PATH"];
28251
28485
  if (env["HASNA_DOMAINS_DB_PATH"])
28252
28486
  return env["HASNA_DOMAINS_DB_PATH"];
28253
- const explicit = env["DOMAINS_DIR"] ?? env["HASNA_DOMAINS_DIR"];
28487
+ const explicit = exactAppOverride(env);
28254
28488
  if (explicit) {
28255
- return join2(explicit, "domains.db");
28489
+ return join4(explicit, "domains.db");
28256
28490
  }
28257
- const home = canonicalHome(env);
28258
- const canonicalDir = join2(home, ".hasna", "domains");
28259
- migrateLegacyDataDir(env);
28260
- migrateDotfile("domains", canonicalDir, env);
28261
- return join2(canonicalDir, "domains.db");
28491
+ if (!adoptResolverHome(resolverHome(env), env)) {
28492
+ migrateLegacyDataDir(env);
28493
+ migrateDotfile("domains", legacyHomeDir(env), env);
28494
+ }
28495
+ return getDefaultDbPath(env);
28262
28496
  }
28263
28497
  function migrateDotfile(name, newDir, env) {
28264
28498
  const home = canonicalHome(env);
28265
- const oldDir = join2(home, `.${name}`);
28266
- if (!existsSync(oldDir) || existsSync(newDir))
28499
+ const oldDir = join4(home, `.${name}`);
28500
+ if (!existsSync2(oldDir) || existsSync2(newDir))
28267
28501
  return;
28268
28502
  mkdirSync(newDir, { recursive: true });
28269
28503
  for (const file of readdirSync(oldDir)) {
28270
- const oldPath = join2(oldDir, file);
28504
+ const oldPath = join4(oldDir, file);
28271
28505
  if (statSync2(oldPath).isFile())
28272
- copyFileSync(oldPath, join2(newDir, file));
28506
+ copyFileSync(oldPath, join4(newDir, file));
28273
28507
  }
28274
28508
  }
28275
28509
  function getDatabase() {
@@ -28277,7 +28511,7 @@ function getDatabase() {
28277
28511
  return _db;
28278
28512
  const dbPath = getDbPath();
28279
28513
  if (dbPath !== ":memory:") {
28280
- const dir = dirname(resolve(dbPath));
28514
+ const dir = dirname(resolve2(dbPath));
28281
28515
  mkdirSync(dir, { recursive: true });
28282
28516
  }
28283
28517
  _db = new Database(dbPath);
@@ -29168,7 +29402,7 @@ function deleteDomainReputation(id) {
29168
29402
  }
29169
29403
 
29170
29404
  // src/db/store.ts
29171
- var APP = "domains";
29405
+ var APP2 = "domains";
29172
29406
  var DOMAINS_PAGE_SIZE = 1000;
29173
29407
  class LocalStore {
29174
29408
  transport = "local";
@@ -29781,7 +30015,7 @@ function assertNoStoreConflict(env) {
29781
30015
  throw new Error(`Refusing to resolve the hosted domains store while ${pathVar} is set: that variable ` + `names a local sqlite file, so the configuration asks for BOTH stores at once and ` + `nothing here can tell which you meant. Writing to the wrong one is silent \u2014 a plain ` + `\`bun run\` script that set ${pathVar} put 230 rows into the production portfolio on ` + `2026-08-07 while reporting success. Pick one: unset HASNA_DOMAINS_API_URL and ` + `HASNA_DOMAINS_API_KEY to use ${pathVar}; unset ${pathVar} to use the hosted store; or set ` + `${ALLOW_CLOUD_WITH_LOCAL_PATH}=1 if you really intend the hosted store with that variable present.`);
29782
30016
  }
29783
30017
  function requireHostedClient(env, flip) {
29784
- const resolved = resolveStorageClient(APP, withoutRetiredModeKeys(env));
30018
+ const resolved = resolveStorageClient(APP2, withoutRetiredModeKeys(env));
29785
30019
  if (resolved.transport !== "http") {
29786
30020
  throw new Error(`Hosted domains client was requested (${flip.urlSource} + ${flip.keySource}) but ` + `@hasna/contracts resolved transport '${resolved.transport}'. Refusing to read the wrong dataset.`);
29787
30021
  }
@@ -29802,7 +30036,7 @@ import { domainToASCII } from "url";
29802
30036
 
29803
30037
  // src/lib/version.ts
29804
30038
  import { readFileSync as readFileSync3 } from "fs";
29805
- import { dirname as dirname2, resolve as resolve2 } from "path";
30039
+ import { dirname as dirname2, resolve as resolve3 } from "path";
29806
30040
  import { fileURLToPath } from "url";
29807
30041
  var cachedVersion = null;
29808
30042
  function getPackageVersion() {
@@ -29810,7 +30044,7 @@ function getPackageVersion() {
29810
30044
  return cachedVersion;
29811
30045
  try {
29812
30046
  const moduleDir = dirname2(fileURLToPath(import.meta.url));
29813
- const packageJsonPath = resolve2(moduleDir, "../../package.json");
30047
+ const packageJsonPath = resolve3(moduleDir, "../../package.json");
29814
30048
  const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
29815
30049
  cachedVersion = pkg.version ?? "0.0.0";
29816
30050
  } catch {
@@ -39466,24 +39700,24 @@ async function syncAll(dbFns) {
39466
39700
 
39467
39701
  // src/lib/config.ts
39468
39702
  import { createHash as createHash3 } from "crypto";
39469
- import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
39470
- import { homedir as homedir3 } from "os";
39471
- import { dirname as dirname4, join as join4 } from "path";
39703
+ import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
39704
+ import { homedir as homedir5 } from "os";
39705
+ import { dirname as dirname4, join as join6 } from "path";
39472
39706
  function canonicalHome2(env) {
39473
- return env["HOME"] || env["USERPROFILE"] || homedir3();
39707
+ return env["HOME"] || env["USERPROFILE"] || homedir5();
39474
39708
  }
39475
39709
  function migrateLegacyConfig(env = process.env, dryRun = false) {
39476
39710
  const report = { dryRun, wouldCopy: false, copied: false };
39477
39711
  const home = canonicalHome2(env);
39478
- const canonicalDir = join4(home, ".hasna", "domains");
39479
- const newPath = join4(canonicalDir, "config.json");
39480
- if (existsSync2(newPath))
39712
+ const canonicalDir = join6(home, ".hasna", "domains");
39713
+ const newPath = join6(canonicalDir, "config.json");
39714
+ if (existsSync3(newPath))
39481
39715
  return report;
39482
- if (existsSync2(join4(canonicalDir, ".migrated-from-xdg-config.receipt.json")))
39716
+ if (existsSync3(join6(canonicalDir, ".migrated-from-xdg-config.receipt.json")))
39483
39717
  return report;
39484
- const xdgConfig = env["XDG_CONFIG_HOME"]?.trim() || join4(home, ".config");
39485
- const oldPath = join4(xdgConfig, "open-domains", "config.json");
39486
- if (!existsSync2(oldPath))
39718
+ const xdgConfig = env["XDG_CONFIG_HOME"]?.trim() || join6(home, ".config");
39719
+ const oldPath = join6(xdgConfig, "open-domains", "config.json");
39720
+ if (!existsSync3(oldPath))
39487
39721
  return report;
39488
39722
  report.wouldCopy = true;
39489
39723
  if (dryRun)
@@ -39495,7 +39729,7 @@ function migrateLegacyConfig(env = process.env, dryRun = false) {
39495
39729
  if (!oldBytes.equals(newBytes)) {
39496
39730
  throw new Error(`Refusing migration: copied ${newPath} does not byte-match ${oldPath}; the canonical config was not populated.`);
39497
39731
  }
39498
- writeFileSync2(join4(canonicalDir, ".migrated-from-xdg-config.receipt.json"), `${JSON.stringify({
39732
+ writeFileSync2(join6(canonicalDir, ".migrated-from-xdg-config.receipt.json"), `${JSON.stringify({
39499
39733
  migratedAt: new Date().toISOString(),
39500
39734
  from: oldPath,
39501
39735
  to: newPath,
@@ -39511,13 +39745,15 @@ function getConfigPath(env = process.env) {
39511
39745
  return env["DOMAINS_CONFIG_PATH"];
39512
39746
  const dir = env["DOMAINS_CONFIG_DIR"];
39513
39747
  if (dir)
39514
- return join4(dir, "config.json");
39515
- migrateLegacyConfig(env);
39516
- return join4(canonicalHome2(env), ".hasna", "domains", "config.json");
39748
+ return join6(dir, "config.json");
39749
+ if (!adoptResolverHome(resolverHome(env), env)) {
39750
+ migrateLegacyConfig(env);
39751
+ }
39752
+ return getDefaultConfigPath(env);
39517
39753
  }
39518
39754
  function loadConfig4(env = process.env) {
39519
39755
  const path = getConfigPath(env);
39520
- if (!existsSync2(path))
39756
+ if (!existsSync3(path))
39521
39757
  return {};
39522
39758
  try {
39523
39759
  return JSON.parse(readFileSync5(path, "utf-8"));