@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/cli/index.js CHANGED
@@ -2084,6 +2084,7 @@ var require_commander = __commonJS((exports) => {
2084
2084
  // ../contracts/dist/client/storage.js
2085
2085
  import { isIP } from "net";
2086
2086
  import { readFileSync, statSync } from "fs";
2087
+ import { createRequire } from "module";
2087
2088
  import { join } from "path";
2088
2089
  function envToken(name) {
2089
2090
  return name.toUpperCase().replace(/-/g, "_");
@@ -2098,24 +2099,48 @@ function clientTransportEnvKeys(name) {
2098
2099
  function credentialOverrideEnvKey(name) {
2099
2100
  return `HASNA_${envToken(name)}_API_KEY_OVERRIDE`;
2100
2101
  }
2102
+ function credentialPointerEnvKey(name) {
2103
+ return `HASNA_${envToken(name)}_API_KEY_REF`;
2104
+ }
2101
2105
  function homeDir(env) {
2102
2106
  const home = env.HOME?.trim();
2103
2107
  return home ? home : null;
2104
2108
  }
2105
- function credentialDiskSources(name, env) {
2106
- return profileDiskSources(name, env, null);
2107
- }
2108
- function profileDiskSources(name, env, profile) {
2109
+ function credentialDiskSourceList(name, env, profile = null) {
2109
2110
  const home = homeDir(env);
2110
2111
  if (!home || !SAFE_APP_SLUG.test(name))
2111
2112
  return [];
2112
2113
  const stem = profile ? `${name}.${profile}` : name;
2113
2114
  const configStem = profile ? `${name}-${profile}` : name;
2114
2115
  return [
2115
- join(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
2116
- join(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`)
2116
+ {
2117
+ path: join(home, HASNA_STATE_DIR, FLEET_CREDENTIAL_DIR, `${stem}.env`),
2118
+ tier: "fleet-env",
2119
+ deprecated: false
2120
+ },
2121
+ {
2122
+ path: join(home, HASNA_STATE_DIR, LEGACY_CLOUD_DIR, `${stem}.env`),
2123
+ tier: "legacy-cloud",
2124
+ deprecated: true
2125
+ },
2126
+ {
2127
+ path: join(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}.env`),
2128
+ tier: "config",
2129
+ deprecated: false
2130
+ },
2131
+ {
2132
+ path: join(home, CONFIG_DIR, CONFIG_NAMESPACE, `${configStem}-cloud.env`),
2133
+ tier: "config-legacy",
2134
+ deprecated: true
2135
+ }
2117
2136
  ];
2118
2137
  }
2138
+ function credentialDiskSources(name, env) {
2139
+ return credentialDiskSourceList(name, env, null).map((s) => s.path);
2140
+ }
2141
+ function profileDiskSources(name, env, profile) {
2142
+ return credentialDiskSourceList(name, env, profile).map((s) => s.path);
2143
+ }
2119
2144
  function parseEnvFile(text) {
2120
2145
  const values = new Map;
2121
2146
  for (const rawLine of text.split(/\r?\n/)) {
@@ -2182,6 +2207,9 @@ function appConfigDiskValue(name, env, keys) {
2182
2207
  return null;
2183
2208
  }
2184
2209
  function assertUsableCredential(appName, source, value) {
2210
+ if (VAULT_POINTER_SHAPE.test(value)) {
2211
+ 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]);
2212
+ }
2185
2213
  if (!ILLEGAL_IN_HEADER_VALUE.test(value))
2186
2214
  return;
2187
2215
  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]);
@@ -2203,6 +2231,14 @@ function sealCredential(fields) {
2203
2231
  writable: false,
2204
2232
  configurable: false
2205
2233
  });
2234
+ if (fields.pointerVaultKey !== undefined) {
2235
+ Object.defineProperty(sealed, "pointerVaultKey", {
2236
+ value: fields.pointerVaultKey,
2237
+ enumerable: false,
2238
+ writable: false,
2239
+ configurable: false
2240
+ });
2241
+ }
2206
2242
  Object.defineProperty(sealed, INSPECT_CUSTOM, {
2207
2243
  value: () => ({ ...visible, apiKey: "[redacted]" }),
2208
2244
  enumerable: false,
@@ -2254,7 +2290,8 @@ function validateAndSealResolvedCredential(appName, credential) {
2254
2290
  deliberate: credential.deliberate,
2255
2291
  deprecated: credential.deprecated,
2256
2292
  diskCandidates: credential.diskCandidates,
2257
- warning: credential.warning
2293
+ warning: credential.warning,
2294
+ ...credential.pointerVaultKey !== undefined ? { pointerVaultKey: credential.pointerVaultKey } : {}
2258
2295
  });
2259
2296
  }
2260
2297
  function firstEnvValue(env, keys) {
@@ -2314,6 +2351,27 @@ function resolveCredential(name, env, options = {}) {
2314
2351
  warning: null
2315
2352
  });
2316
2353
  }
2354
+ const pointerKeyName = credentialPointerEnvKey(name);
2355
+ const pointerRaw = env[pointerKeyName];
2356
+ if (pointerRaw !== undefined) {
2357
+ const pointer = pointerRaw.trim();
2358
+ if (!pointer) {
2359
+ 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]);
2360
+ }
2361
+ if (!VAULT_POINTER_SHAPE.test(pointer)) {
2362
+ 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]);
2363
+ }
2364
+ return sealCredential({
2365
+ apiKey: "",
2366
+ pointerVaultKey: pointer,
2367
+ tier: "pointer",
2368
+ source: pointerKeyName,
2369
+ deliberate: true,
2370
+ deprecated: false,
2371
+ diskCandidates: diskPaths,
2372
+ warning: null
2373
+ });
2374
+ }
2317
2375
  const profile = options.profile?.trim() || env[CREDENTIAL_PROFILE_ENV_KEY]?.trim();
2318
2376
  if (profile) {
2319
2377
  const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
@@ -2338,26 +2396,42 @@ function resolveCredential(name, env, options = {}) {
2338
2396
  }
2339
2397
  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);
2340
2398
  }
2341
- const diskHits = diskPaths.map((path) => ({ path, value: readCredentialFile(path, apiKeyKeys) })).filter((hit) => hit.value !== null);
2399
+ const diskSourceList = credentialDiskSourceList(name, env, null);
2400
+ const diskHits = diskSourceList.map((src) => ({ src, value: readCredentialFile(src.path, apiKeyKeys) })).filter((hit) => hit.value !== null);
2342
2401
  if (diskHits.length > 0) {
2343
2402
  const winner = diskHits[0];
2344
- assertUsableCredential(name, winner.path, winner.value);
2403
+ assertUsableCredential(name, winner.src.path, winner.value);
2345
2404
  const divergentSources = [
2346
- ...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.path),
2405
+ ...diskHits.slice(1).filter((hit) => hit.value !== winner.value).map((hit) => hit.src.path),
2347
2406
  ...(() => {
2348
2407
  const legacyHit = firstEnvValue(env, apiKeyKeys);
2349
2408
  return legacyHit && legacyHit.value !== winner.value ? [legacyHit.key] : [];
2350
2409
  })()
2351
2410
  ];
2352
- 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;
2411
+ 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;
2412
+ let deprecated = winner.src.deprecated;
2413
+ let finalWarning = warning;
2414
+ if (winner.src.deprecated) {
2415
+ deprecated = true;
2416
+ const sink = options.onDeprecation ?? defaultDeprecationSink;
2417
+ const notified = deprecationNotified();
2418
+ const noticeKey = `${name}:${winner.src.path}`;
2419
+ if (!notified.has(noticeKey)) {
2420
+ notified.add(noticeKey);
2421
+ const target = diskSourceList[0]?.path ?? "<none>";
2422
+ 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.`;
2423
+ sink(message);
2424
+ }
2425
+ finalWarning = [warning, `Legacy credential source: ${winner.src.path}. Removed after ${LEGACY_CLOUD_REMOVAL_DEADLINE}.`].filter(Boolean).join(" ") || null;
2426
+ }
2353
2427
  return sealCredential({
2354
2428
  apiKey: winner.value,
2355
- tier: "disk",
2356
- source: winner.path,
2429
+ tier: winner.src.tier,
2430
+ source: winner.src.path,
2357
2431
  deliberate: false,
2358
- deprecated: false,
2432
+ deprecated,
2359
2433
  diskCandidates: diskPaths,
2360
- warning
2434
+ warning: finalWarning
2361
2435
  });
2362
2436
  }
2363
2437
  const legacy = firstEnvValue(env, apiKeyKeys);
@@ -2383,6 +2457,45 @@ function resolveCredential(name, env, options = {}) {
2383
2457
  }
2384
2458
  return null;
2385
2459
  }
2460
+ async function completePointerCredential(name, pointerResolution, env = process.env) {
2461
+ const vaultKey = pointerResolution.pointerVaultKey;
2462
+ const pointerEnvKey = pointerResolution.source;
2463
+ if (!vaultKey) {
2464
+ throw new CredentialResolutionError(name, `Pointer resolution from ${pointerEnvKey} carries no vault item key; this is a defect in the resolver.`, [pointerEnvKey]);
2465
+ }
2466
+ let secretsSdk;
2467
+ try {
2468
+ secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
2469
+ } catch {
2470
+ 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]);
2471
+ }
2472
+ let client;
2473
+ try {
2474
+ client = secretsSdk.createSecretsClientFromEnv(env);
2475
+ } catch {
2476
+ 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]);
2477
+ }
2478
+ let secret;
2479
+ try {
2480
+ secret = await client.getSecret({ key: vaultKey });
2481
+ } catch {
2482
+ 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]);
2483
+ }
2484
+ const value = secret.value;
2485
+ if (!value) {
2486
+ throw new CredentialResolutionError(name, `${pointerEnvKey} resolved vault item '${vaultKey}', but it holds no value. A vault pointer is TERMINAL.`, [pointerEnvKey]);
2487
+ }
2488
+ assertUsableCredential(name, `${pointerEnvKey} -> vault:${vaultKey}`, value);
2489
+ return sealCredential({
2490
+ apiKey: value,
2491
+ tier: "pointer",
2492
+ source: `${pointerEnvKey} -> vault:${vaultKey}`,
2493
+ deliberate: true,
2494
+ deprecated: false,
2495
+ diskCandidates: pointerResolution.diskCandidates,
2496
+ warning: null
2497
+ });
2498
+ }
2386
2499
  function isValidDnsDomain(value) {
2387
2500
  if (value.length === 0 || value.length > 253 || ASCII_CONTROL_PATTERN.test(value) || /[^\x00-\x7f]/.test(value)) {
2388
2501
  return false;
@@ -2606,6 +2719,13 @@ function currentCredential(name, apiKey) {
2606
2719
  }
2607
2720
  return explicitCredential(name, apiKey);
2608
2721
  }
2722
+ async function resolveRequestCredential(name, apiKey, env = process.env) {
2723
+ const resolved = currentCredential(name, apiKey);
2724
+ if (resolved.tier === "pointer") {
2725
+ return completePointerCredential(name, resolved, env);
2726
+ }
2727
+ return resolved;
2728
+ }
2609
2729
  function authFailureGuidance(credential) {
2610
2730
  const origin = `The API key for this request came from ${credential.source}`;
2611
2731
  if (credential.deliberate) {
@@ -2751,7 +2871,7 @@ function createHasnaHttpTransport(options) {
2751
2871
  const retry = resolveRetry(opts.retry);
2752
2872
  const methodRetryable = IDEMPOTENT_METHODS.has(upper) || Boolean(opts.idempotencyKey);
2753
2873
  const maxAttempts = retry && methodRetryable ? retry.retries + 1 : 1;
2754
- const credential = currentCredential(options.name, options.apiKey);
2874
+ const credential = await resolveRequestCredential(options.name, options.apiKey);
2755
2875
  let last = null;
2756
2876
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
2757
2877
  const result = await once(upper, rel, url, body, opts, credential);
@@ -2914,7 +3034,7 @@ function resolveStorageClient(name, env = process.env, overrides) {
2914
3034
  }
2915
3035
  return { transport: "sqlite", client: null };
2916
3036
  }
2917
- var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, HASNA_STATE_DIR = ".hasna", FLEET_CREDENTIAL_DIR = "cloud", CONFIG_DIR = ".config", CONFIG_NAMESPACE = "hasna", MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", DEPRECATION_REGISTRY, ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3037
+ var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, HASNA_STATE_DIR = ".hasna", FLEET_CREDENTIAL_DIR = "fleet-env", LEGACY_CLOUD_DIR = "cloud", CONFIG_DIR = ".config", CONFIG_NAMESPACE = "hasna", LEGACY_CLOUD_REMOVAL_DEADLINE = "2026-10-01", MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", DEPRECATION_REGISTRY, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk, ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS, defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2918
3038
  var init_storage = __esm(() => {
2919
3039
  CredentialResolutionError = class CredentialResolutionError extends Error {
2920
3040
  appName;
@@ -2930,10 +3050,13 @@ var init_storage = __esm(() => {
2930
3050
  SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
2931
3051
  SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
2932
3052
  ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
3053
+ VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
2933
3054
  CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
2934
3055
  INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
2935
3056
  CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
2936
3057
  DEPRECATION_REGISTRY = Symbol.for("hasna:contracts:credentialDeprecationNotices");
3058
+ SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
3059
+ requireSecretsSdk = createRequire(import.meta.url);
2937
3060
  ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
2938
3061
  DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
2939
3062
  HasnaHttpError = class HasnaHttpError extends Error {
@@ -2967,6 +3090,7 @@ var init_storage = __esm(() => {
2967
3090
  });
2968
3091
 
2969
3092
  // ../contracts/dist/client/transport.js
3093
+ import { createRequire as createRequire2 } from "module";
2970
3094
  function envToken2(name) {
2971
3095
  return name.toUpperCase().replace(/-/g, "_");
2972
3096
  }
@@ -2977,12 +3101,14 @@ function clientTransportEnvKeys2(name) {
2977
3101
  apiKeyKeys: [`HASNA_${envSegment}_API_KEY`, `${envSegment}_API_KEY`]
2978
3102
  };
2979
3103
  }
2980
- var MAX_CREDENTIAL_FILE_BYTES2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, DEPRECATION_REGISTRY2, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2;
3104
+ var MAX_CREDENTIAL_FILE_BYTES2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, DEPRECATION_REGISTRY2, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk2, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2;
2981
3105
  var init_transport = __esm(() => {
2982
3106
  MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
2983
3107
  INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
2984
3108
  CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
2985
3109
  DEPRECATION_REGISTRY2 = Symbol.for("hasna:contracts:credentialDeprecationNotices");
3110
+ SECRETS_PACKAGE_SPECIFIER2 = "@hasna/" + "secrets";
3111
+ requireSecretsSdk2 = createRequire2(import.meta.url);
2986
3112
  IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
2987
3113
  AUTHORITY_OVERRIDE_HEADERS2 = new Set([
2988
3114
  "host",
@@ -3263,22 +3389,132 @@ var init_migrations = __esm(() => {
3263
3389
  ];
3264
3390
  });
3265
3391
 
3392
+ // ../../node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
3393
+ import { homedir } from "os";
3394
+ import { join as join2 } from "path";
3395
+ function assertApp(app) {
3396
+ if (typeof app !== "string" || app.length === 0) {
3397
+ throw new TypeError("paths: app must be a non-empty string");
3398
+ }
3399
+ if (!APP_SLUG_RE.test(app)) {
3400
+ throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
3401
+ }
3402
+ }
3403
+ function envOf(options) {
3404
+ return options.env ?? process.env;
3405
+ }
3406
+ function envValue(options, kind) {
3407
+ const value = envOf(options)[KIND_ENV[kind]];
3408
+ return typeof value === "string" && value.length > 0 ? value : undefined;
3409
+ }
3410
+ function isMacOS(platform) {
3411
+ return platform === "darwin";
3412
+ }
3413
+ function baseDir(kind, options) {
3414
+ const override = envValue(options, kind);
3415
+ if (override)
3416
+ return override;
3417
+ const home = options.home ?? homedir();
3418
+ const platform = options.platform ?? process.platform;
3419
+ if (isMacOS(platform)) {
3420
+ switch (kind) {
3421
+ case "config":
3422
+ case "data":
3423
+ return join2(home, "Library", "Application Support", "Hasna");
3424
+ case "cache":
3425
+ return join2(home, "Library", "Caches", "Hasna");
3426
+ case "state":
3427
+ return join2(home, "Library", "Logs", "Hasna");
3428
+ }
3429
+ }
3430
+ switch (kind) {
3431
+ case "config":
3432
+ return join2(home, ".config", "hasna");
3433
+ case "data":
3434
+ return join2(home, ".local", "share", "hasna");
3435
+ case "state":
3436
+ return join2(home, ".local", "state", "hasna");
3437
+ case "cache":
3438
+ return join2(home, ".cache", "hasna");
3439
+ }
3440
+ }
3441
+ function resolvePath(kind, options) {
3442
+ assertApp(options.app);
3443
+ const appSegment = options.internal === true ? join2("internal", options.app) : options.app;
3444
+ return join2(baseDir(kind, options), appSegment);
3445
+ }
3446
+ function dataDir(options) {
3447
+ return resolvePath("data", options);
3448
+ }
3449
+ var KIND_ENV, APP_SLUG_RE;
3450
+ var init_dist = __esm(() => {
3451
+ KIND_ENV = {
3452
+ config: "HASNA_CONFIG_HOME",
3453
+ data: "HASNA_DATA_HOME",
3454
+ state: "HASNA_STATE_HOME",
3455
+ cache: "HASNA_CACHE_HOME"
3456
+ };
3457
+ APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3458
+ });
3459
+
3460
+ // src/lib/app-home.ts
3461
+ import { existsSync } from "fs";
3462
+ import { homedir as homedir2 } from "os";
3463
+ import { join as join3, resolve } from "path";
3464
+ function effectiveHome(env = process.env) {
3465
+ return env["HOME"] || env["USERPROFILE"] || homedir2();
3466
+ }
3467
+ function legacyHomeDir(env = process.env) {
3468
+ return join3(effectiveHome(env), ".hasna", APP);
3469
+ }
3470
+ function resolverHome(env = process.env) {
3471
+ const home = env["HOME"] || env["USERPROFILE"];
3472
+ return dataDir({ app: APP, home, env });
3473
+ }
3474
+ function adoptResolverHome(resolved, env = process.env) {
3475
+ const dataOverride = env.HASNA_DATA_HOME;
3476
+ if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
3477
+ return true;
3478
+ return existsSync(join3(resolved, "domains.db"));
3479
+ }
3480
+ function exactAppOverride(env = process.env) {
3481
+ const override = env["HASNA_DOMAINS_HOME"] ?? env["DOMAINS_HOME"] ?? env["HASNA_DOMAINS_DIR"] ?? env["DOMAINS_DIR"];
3482
+ return override && override.trim() ? override.trim() : undefined;
3483
+ }
3484
+ function appHome(env = process.env) {
3485
+ const override = exactAppOverride(env);
3486
+ if (override)
3487
+ return resolve(override);
3488
+ const resolved = resolverHome(env);
3489
+ return adoptResolverHome(resolved, env) ? resolve(resolved) : resolve(legacyHomeDir(env));
3490
+ }
3491
+ function getDefaultDbPath(env = process.env) {
3492
+ return join3(appHome(env), `${APP}.db`);
3493
+ }
3494
+ function getDefaultConfigPath(env = process.env) {
3495
+ return join3(appHome(env), "config.json");
3496
+ }
3497
+ var APP = "domains";
3498
+ var init_app_home = __esm(() => {
3499
+ init_dist();
3500
+ });
3501
+
3266
3502
  // src/db/database.ts
3267
3503
  import { Database } from "bun:sqlite";
3268
3504
  import { createHash } from "crypto";
3269
3505
  import {
3270
3506
  copyFileSync,
3271
- existsSync,
3507
+ existsSync as existsSync2,
3272
3508
  mkdirSync,
3273
3509
  readFileSync as readFileSync2,
3274
3510
  readdirSync,
3275
3511
  statSync as statSync2,
3276
3512
  writeFileSync
3277
3513
  } from "fs";
3278
- import { dirname, join as join2, resolve } from "path";
3279
- import { homedir } from "os";
3514
+ import { dirname, join as join4, resolve as resolve2 } from "path";
3515
+ import { homedir as homedir3 } from "os";
3280
3516
  function canonicalHome(env) {
3281
- return env["HOME"] || env["USERPROFILE"] || homedir();
3517
+ return env["HOME"] || env["USERPROFILE"] || homedir3();
3282
3518
  }
3283
3519
  function sha256File(path) {
3284
3520
  return createHash("sha256").update(readFileSync2(path)).digest("hex");
@@ -3286,20 +3522,20 @@ function sha256File(path) {
3286
3522
  function migrateLegacyDataDir(env = process.env, dryRun = false) {
3287
3523
  const report = { dryRun, wouldCopy: [], copied: [] };
3288
3524
  const home = canonicalHome(env);
3289
- const xdgData = env["XDG_DATA_HOME"]?.trim() || join2(home, ".local", "share");
3290
- const oldDir = join2(xdgData, "open-domains");
3291
- const oldDb = join2(oldDir, "domains.db");
3292
- if (!existsSync(oldDb))
3525
+ const xdgData = env["XDG_DATA_HOME"]?.trim() || join4(home, ".local", "share");
3526
+ const oldDir = join4(xdgData, "open-domains");
3527
+ const oldDb = join4(oldDir, "domains.db");
3528
+ if (!existsSync2(oldDb))
3293
3529
  return report;
3294
- const canonicalDir = join2(home, ".hasna", "domains");
3295
- const newDb = join2(canonicalDir, "domains.db");
3296
- if (existsSync(newDb))
3530
+ const canonicalDir = join4(home, ".hasna", "domains");
3531
+ const newDb = join4(canonicalDir, "domains.db");
3532
+ if (existsSync2(newDb))
3297
3533
  return report;
3298
- if (existsSync(join2(canonicalDir, ".migrated-from-xdg.receipt.json")))
3534
+ if (existsSync2(join4(canonicalDir, ".migrated-from-xdg.receipt.json")))
3299
3535
  return report;
3300
3536
  if (dryRun) {
3301
3537
  for (const name of ["domains.db", "domains.db-wal", "domains.db-shm"]) {
3302
- if (existsSync(join2(oldDir, name)) && !existsSync(join2(canonicalDir, name))) {
3538
+ if (existsSync2(join4(oldDir, name)) && !existsSync2(join4(canonicalDir, name))) {
3303
3539
  report.wouldCopy.push(name);
3304
3540
  }
3305
3541
  }
@@ -3308,11 +3544,11 @@ function migrateLegacyDataDir(env = process.env, dryRun = false) {
3308
3544
  mkdirSync(canonicalDir, { recursive: true });
3309
3545
  const copied = [];
3310
3546
  for (const name of ["domains.db", "domains.db-wal", "domains.db-shm"]) {
3311
- const from = join2(oldDir, name);
3312
- if (!existsSync(from))
3547
+ const from = join4(oldDir, name);
3548
+ if (!existsSync2(from))
3313
3549
  continue;
3314
- const to = join2(canonicalDir, name);
3315
- if (existsSync(to))
3550
+ const to = join4(canonicalDir, name);
3551
+ if (existsSync2(to))
3316
3552
  continue;
3317
3553
  copyFileSync(from, to);
3318
3554
  copied.push({ name, bytes: statSync2(to).size, sha256: sha256File(to) });
@@ -3321,7 +3557,7 @@ function migrateLegacyDataDir(env = process.env, dryRun = false) {
3321
3557
  if (statSync2(newDb).size !== statSync2(oldDb).size || sha256File(newDb) !== sha256File(oldDb)) {
3322
3558
  throw new Error(`Refusing migration: copied ${newDb} does not byte-match ${oldDb}; the canonical root was not populated.`);
3323
3559
  }
3324
- writeFileSync(join2(canonicalDir, ".migrated-from-xdg.receipt.json"), `${JSON.stringify({
3560
+ writeFileSync(join4(canonicalDir, ".migrated-from-xdg.receipt.json"), `${JSON.stringify({
3325
3561
  migratedAt: new Date().toISOString(),
3326
3562
  from: oldDir,
3327
3563
  to: canonicalDir,
@@ -3335,26 +3571,26 @@ function getDbPath(env = process.env) {
3335
3571
  return env["DOMAINS_DB_PATH"];
3336
3572
  if (env["HASNA_DOMAINS_DB_PATH"])
3337
3573
  return env["HASNA_DOMAINS_DB_PATH"];
3338
- const explicit = env["DOMAINS_DIR"] ?? env["HASNA_DOMAINS_DIR"];
3574
+ const explicit = exactAppOverride(env);
3339
3575
  if (explicit) {
3340
- return join2(explicit, "domains.db");
3576
+ return join4(explicit, "domains.db");
3341
3577
  }
3342
- const home = canonicalHome(env);
3343
- const canonicalDir = join2(home, ".hasna", "domains");
3344
- migrateLegacyDataDir(env);
3345
- migrateDotfile("domains", canonicalDir, env);
3346
- return join2(canonicalDir, "domains.db");
3578
+ if (!adoptResolverHome(resolverHome(env), env)) {
3579
+ migrateLegacyDataDir(env);
3580
+ migrateDotfile("domains", legacyHomeDir(env), env);
3581
+ }
3582
+ return getDefaultDbPath(env);
3347
3583
  }
3348
3584
  function migrateDotfile(name, newDir, env) {
3349
3585
  const home = canonicalHome(env);
3350
- const oldDir = join2(home, `.${name}`);
3351
- if (!existsSync(oldDir) || existsSync(newDir))
3586
+ const oldDir = join4(home, `.${name}`);
3587
+ if (!existsSync2(oldDir) || existsSync2(newDir))
3352
3588
  return;
3353
3589
  mkdirSync(newDir, { recursive: true });
3354
3590
  for (const file of readdirSync(oldDir)) {
3355
- const oldPath = join2(oldDir, file);
3591
+ const oldPath = join4(oldDir, file);
3356
3592
  if (statSync2(oldPath).isFile())
3357
- copyFileSync(oldPath, join2(newDir, file));
3593
+ copyFileSync(oldPath, join4(newDir, file));
3358
3594
  }
3359
3595
  }
3360
3596
  function getDatabase() {
@@ -3362,7 +3598,7 @@ function getDatabase() {
3362
3598
  return _db;
3363
3599
  const dbPath = getDbPath();
3364
3600
  if (dbPath !== ":memory:") {
3365
- const dir = dirname(resolve(dbPath));
3601
+ const dir = dirname(resolve2(dbPath));
3366
3602
  mkdirSync(dir, { recursive: true });
3367
3603
  }
3368
3604
  _db = new Database(dbPath);
@@ -3395,6 +3631,7 @@ function getDatabase() {
3395
3631
  var _db = null;
3396
3632
  var init_database = __esm(() => {
3397
3633
  init_migrations();
3634
+ init_app_home();
3398
3635
  });
3399
3636
 
3400
3637
  // src/db/domain-records.ts
@@ -4898,7 +5135,7 @@ function assertNoStoreConflict(env) {
4898
5135
  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.`);
4899
5136
  }
4900
5137
  function requireHostedClient(env, flip) {
4901
- const resolved = resolveStorageClient(APP, withoutRetiredModeKeys(env));
5138
+ const resolved = resolveStorageClient(APP2, withoutRetiredModeKeys(env));
4902
5139
  if (resolved.transport !== "http") {
4903
5140
  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.`);
4904
5141
  }
@@ -4923,7 +5160,7 @@ function isCloudStore(env = process.env) {
4923
5160
  requireHostedClient(env, flip);
4924
5161
  return true;
4925
5162
  }
4926
- var APP = "domains", DOMAINS_PAGE_SIZE = 1000, RETIRED_MODE_KEYS, ALLOW_CLOUD_IN_TESTS = "HASNA_DOMAINS_ALLOW_CLOUD_IN_TESTS", ALLOW_CLOUD_WITH_LOCAL_PATH = "HASNA_DOMAINS_ALLOW_CLOUD_WITH_LOCAL_PATH", LOCAL_PATH_VARS, warnedCloudDowngrade = false;
5163
+ var APP2 = "domains", DOMAINS_PAGE_SIZE = 1000, RETIRED_MODE_KEYS, ALLOW_CLOUD_IN_TESTS = "HASNA_DOMAINS_ALLOW_CLOUD_IN_TESTS", ALLOW_CLOUD_WITH_LOCAL_PATH = "HASNA_DOMAINS_ALLOW_CLOUD_WITH_LOCAL_PATH", LOCAL_PATH_VARS, warnedCloudDowngrade = false;
4927
5164
  var init_store = __esm(() => {
4928
5165
  init_storage();
4929
5166
  init_transport();
@@ -4949,14 +5186,14 @@ var init_store = __esm(() => {
4949
5186
 
4950
5187
  // src/lib/version.ts
4951
5188
  import { readFileSync as readFileSync3 } from "fs";
4952
- import { dirname as dirname2, resolve as resolve2 } from "path";
5189
+ import { dirname as dirname2, resolve as resolve3 } from "path";
4953
5190
  import { fileURLToPath } from "url";
4954
5191
  function getPackageVersion() {
4955
5192
  if (cachedVersion)
4956
5193
  return cachedVersion;
4957
5194
  try {
4958
5195
  const moduleDir = dirname2(fileURLToPath(import.meta.url));
4959
- const packageJsonPath = resolve2(moduleDir, "../../package.json");
5196
+ const packageJsonPath = resolve3(moduleDir, "../../package.json");
4960
5197
  const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
4961
5198
  cachedVersion = pkg.version ?? "0.0.0";
4962
5199
  } catch {
@@ -7188,7 +7425,7 @@ var require_client = __commonJS((exports) => {
7188
7425
  };
7189
7426
  };
7190
7427
  var sleep = (seconds) => {
7191
- return new Promise((resolve3) => setTimeout(resolve3, seconds * 1000));
7428
+ return new Promise((resolve4) => setTimeout(resolve4, seconds * 1000));
7192
7429
  };
7193
7430
  var waiterServiceDefaults = {
7194
7431
  minDelay: 2,
@@ -7317,8 +7554,8 @@ var require_client = __commonJS((exports) => {
7317
7554
  };
7318
7555
  var abortTimeout = (abortSignal) => {
7319
7556
  let onAbort;
7320
- const promise = new Promise((resolve3) => {
7321
- onAbort = () => resolve3({ state: WaiterState.ABORTED });
7557
+ const promise = new Promise((resolve4) => {
7558
+ onAbort = () => resolve4({ state: WaiterState.ABORTED });
7322
7559
  if (typeof abortSignal.addEventListener === "function") {
7323
7560
  abortSignal.addEventListener("abort", onAbort);
7324
7561
  } else {
@@ -7971,8 +8208,8 @@ var require_client = __commonJS((exports) => {
7971
8208
 
7972
8209
  // ../../node_modules/.bun/@smithy+core@3.33.2/node_modules/@smithy/core/dist-cjs/submodules/config/index.js
7973
8210
  var require_config = __commonJS((exports) => {
7974
- var { homedir: homedir2 } = __require("os");
7975
- var { sep, join: join3 } = __require("path");
8211
+ var { homedir: homedir4 } = __require("os");
8212
+ var { sep, join: join5 } = __require("path");
7976
8213
  var { createHash: createHash2 } = __require("crypto");
7977
8214
  var { readFile: readFile$1 } = __require("fs/promises");
7978
8215
  var { IniSectionType } = require_dist_cjs();
@@ -8121,7 +8358,7 @@ var require_config = __commonJS((exports) => {
8121
8358
  return `${HOMEDRIVE}${HOMEPATH}`;
8122
8359
  const homeDirCacheKey = getHomeDirCacheKey();
8123
8360
  if (!homeDirCache[homeDirCacheKey])
8124
- homeDirCache[homeDirCacheKey] = homedir2();
8361
+ homeDirCache[homeDirCacheKey] = homedir4();
8125
8362
  return homeDirCache[homeDirCacheKey];
8126
8363
  };
8127
8364
  var ENV_PROFILE = "AWS_PROFILE";
@@ -8130,7 +8367,7 @@ var require_config = __commonJS((exports) => {
8130
8367
  var getSSOTokenFilepath = (id) => {
8131
8368
  const hasher = createHash2("sha1");
8132
8369
  const cacheName = hasher.update(id).digest("hex");
8133
- return join3(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
8370
+ return join5(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
8134
8371
  };
8135
8372
  var tokenIntercept = {};
8136
8373
  var getSSOTokenFromFile = async (id) => {
@@ -8157,9 +8394,9 @@ var require_config = __commonJS((exports) => {
8157
8394
  ...data.default && { default: data.default }
8158
8395
  });
8159
8396
  var ENV_CONFIG_PATH = "AWS_CONFIG_FILE";
8160
- var getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || join3(getHomeDir(), ".aws", "config");
8397
+ var getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || join5(getHomeDir(), ".aws", "config");
8161
8398
  var ENV_CREDENTIALS_PATH = "AWS_SHARED_CREDENTIALS_FILE";
8162
- var getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || join3(getHomeDir(), ".aws", "credentials");
8399
+ var getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || join5(getHomeDir(), ".aws", "credentials");
8163
8400
  var prefixKeyRegex = /^([\w-]+)\s(["'])?([\w-@+.%:/]+)\2$/;
8164
8401
  var profileNameBlockList = ["__proto__", "profile __proto__"];
8165
8402
  var parseIni = (iniData) => {
@@ -8225,11 +8462,11 @@ var require_config = __commonJS((exports) => {
8225
8462
  const relativeHomeDirPrefix = "~/";
8226
8463
  let resolvedFilepath = filepath;
8227
8464
  if (filepath.startsWith(relativeHomeDirPrefix)) {
8228
- resolvedFilepath = join3(homeDir2, filepath.slice(2));
8465
+ resolvedFilepath = join5(homeDir2, filepath.slice(2));
8229
8466
  }
8230
8467
  let resolvedConfigFilepath = configFilepath;
8231
8468
  if (configFilepath.startsWith(relativeHomeDirPrefix)) {
8232
- resolvedConfigFilepath = join3(homeDir2, configFilepath.slice(2));
8469
+ resolvedConfigFilepath = join5(homeDir2, configFilepath.slice(2));
8233
8470
  }
8234
8471
  const parsedFiles = await Promise.all([
8235
8472
  readFile(resolvedConfigFilepath, {
@@ -8446,7 +8683,7 @@ var require_config = __commonJS((exports) => {
8446
8683
  };
8447
8684
  var imdsRequest = async (options) => {
8448
8685
  const { request } = __require("http");
8449
- return new Promise((resolve3, reject) => {
8686
+ return new Promise((resolve4, reject) => {
8450
8687
  const req = request({
8451
8688
  hostname: options.hostname,
8452
8689
  port: options.port,
@@ -8474,7 +8711,7 @@ var require_config = __commonJS((exports) => {
8474
8711
  const chunks = [];
8475
8712
  res.on("data", (chunk) => chunks.push(chunk));
8476
8713
  res.on("end", () => {
8477
- resolve3(Buffer.concat(chunks));
8714
+ resolve4(Buffer.concat(chunks));
8478
8715
  req.destroy();
8479
8716
  });
8480
8717
  });
@@ -10825,7 +11062,7 @@ ${value}\r
10825
11062
  if (isReadableStream(stream)) {
10826
11063
  return headStream$1(stream, bytes);
10827
11064
  }
10828
- return new Promise((resolve3, reject) => {
11065
+ return new Promise((resolve4, reject) => {
10829
11066
  const collector = new Collector$1;
10830
11067
  collector.limit = bytes;
10831
11068
  stream.pipe(collector);
@@ -10836,7 +11073,7 @@ ${value}\r
10836
11073
  collector.on("error", reject);
10837
11074
  collector.on("finish", function() {
10838
11075
  const bytes2 = concatBytes(this.buffers);
10839
- resolve3(bytes2);
11076
+ resolve4(bytes2);
10840
11077
  });
10841
11078
  });
10842
11079
  };
@@ -10950,7 +11187,7 @@ ${value}\r
10950
11187
  if (isReadableStream(stream)) {
10951
11188
  return collectReadableStream(stream);
10952
11189
  }
10953
- return new Promise((resolve3, reject) => {
11190
+ return new Promise((resolve4, reject) => {
10954
11191
  const collector = new Collector;
10955
11192
  const nodeStream = stream;
10956
11193
  nodeStream.pipe(collector);
@@ -10961,7 +11198,7 @@ ${value}\r
10961
11198
  collector.on("error", reject);
10962
11199
  collector.on("finish", function() {
10963
11200
  const bytes = concatBytes(this.bufferedBytes);
10964
- resolve3(bytes);
11201
+ resolve4(bytes);
10965
11202
  });
10966
11203
  });
10967
11204
  };
@@ -11153,7 +11390,7 @@ var require_checksum = __commonJS((exports) => {
11153
11390
  callback();
11154
11391
  }
11155
11392
  }
11156
- var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve3, reject) => {
11393
+ var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve4, reject) => {
11157
11394
  if (!isReadStream(fileStream)) {
11158
11395
  reject(new Error("Unable to calculate hash for non-file streams."));
11159
11396
  return;
@@ -11171,7 +11408,7 @@ var require_checksum = __commonJS((exports) => {
11171
11408
  });
11172
11409
  hashCalculator.on("error", reject);
11173
11410
  hashCalculator.on("finish", function() {
11174
- hash.digest().then(resolve3).catch(reject);
11411
+ hash.digest().then(resolve4).catch(reject);
11175
11412
  });
11176
11413
  });
11177
11414
  var isReadStream = (stream) => typeof stream.path === "string";
@@ -11182,14 +11419,14 @@ var require_checksum = __commonJS((exports) => {
11182
11419
  const hash = new hashCtor;
11183
11420
  const hashCalculator = new HashCalculator(hash);
11184
11421
  readableStream.pipe(hashCalculator);
11185
- return new Promise((resolve3, reject) => {
11422
+ return new Promise((resolve4, reject) => {
11186
11423
  readableStream.on("error", (err) => {
11187
11424
  hashCalculator.end();
11188
11425
  reject(err);
11189
11426
  });
11190
11427
  hashCalculator.on("error", reject);
11191
11428
  hashCalculator.on("finish", () => {
11192
- hash.digest().then(resolve3).catch(reject);
11429
+ hash.digest().then(resolve4).catch(reject);
11193
11430
  });
11194
11431
  });
11195
11432
  };
@@ -12295,7 +12532,7 @@ var require_event_streams = __commonJS((exports) => {
12295
12532
  streamEnded = true;
12296
12533
  });
12297
12534
  while (!generationEnded) {
12298
- const value = await new Promise((resolve3) => setTimeout(() => resolve3(records.shift()), 0));
12535
+ const value = await new Promise((resolve4) => setTimeout(() => resolve4(records.shift()), 0));
12299
12536
  if (value) {
12300
12537
  yield value;
12301
12538
  }
@@ -13175,8 +13412,8 @@ var require_protocols = __commonJS((exports) => {
13175
13412
  async build() {
13176
13413
  const { hostname, protocol = "https", port, path: basePath } = await this.context.endpoint();
13177
13414
  this.path = basePath;
13178
- for (const resolvePath of this.resolvePathStack) {
13179
- resolvePath(this.path);
13415
+ for (const resolvePath2 of this.resolvePathStack) {
13416
+ resolvePath2(this.path);
13180
13417
  }
13181
13418
  return new HttpRequest({
13182
13419
  protocol,
@@ -13790,7 +14027,7 @@ var require_retry = __commonJS((exports) => {
13790
14027
  }
13791
14028
  };
13792
14029
  }
13793
- var cooldown = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
14030
+ var cooldown = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
13794
14031
  var isRetryStrategyV2 = (retryStrategy) => typeof retryStrategy.acquireInitialRetryToken !== "undefined" && typeof retryStrategy.refreshRetryTokenForRetry !== "undefined" && typeof retryStrategy.recordSuccess !== "undefined";
13795
14032
  var getRetryErrorInfo = (error, logger) => {
13796
14033
  const errorInfo = {
@@ -13889,7 +14126,7 @@ var require_retry = __commonJS((exports) => {
13889
14126
  this.refillTokenBucket();
13890
14127
  while (amount > this.availableTokens) {
13891
14128
  const delay = (amount - this.availableTokens) / this.fillRate * 1000;
13892
- await new Promise((resolve3) => DefaultRateLimiter.setTimeoutFn(resolve3, delay));
14129
+ await new Promise((resolve4) => DefaultRateLimiter.setTimeoutFn(resolve4, delay));
13893
14130
  this.refillTokenBucket();
13894
14131
  }
13895
14132
  this.availableTokens = this.availableTokens - amount;
@@ -14231,7 +14468,7 @@ var require_retry = __commonJS((exports) => {
14231
14468
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
14232
14469
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
14233
14470
  totalDelay += delay;
14234
- await new Promise((resolve3) => setTimeout(resolve3, delay));
14471
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
14235
14472
  continue;
14236
14473
  }
14237
14474
  if (!err.$metadata) {
@@ -17706,7 +17943,7 @@ var init_node_http = () => {};
17706
17943
 
17707
17944
  // ../../node_modules/.bun/@smithy+credential-provider-imds@4.5.2/node_modules/@smithy/credential-provider-imds/dist-es/remoteProvider/httpRequest.js
17708
17945
  function httpRequest(options) {
17709
- return new Promise((resolve3, reject) => {
17946
+ return new Promise((resolve4, reject) => {
17710
17947
  const req = node_http.request({
17711
17948
  method: "GET",
17712
17949
  ...options,
@@ -17731,7 +17968,7 @@ function httpRequest(options) {
17731
17968
  chunks.push(chunk);
17732
17969
  });
17733
17970
  res.on("end", () => {
17734
- resolve3(Buffer.concat(chunks));
17971
+ resolve4(Buffer.concat(chunks));
17735
17972
  req.destroy();
17736
17973
  });
17737
17974
  });
@@ -17955,9 +18192,9 @@ var import_config6, IMDS_PATH = "/latest/meta-data/iam/security-credentials/", I
17955
18192
  let fallbackBlockedFromProcessEnv = false;
17956
18193
  const configValue = await import_config6.loadConfig({
17957
18194
  environmentVariableSelector: (env) => {
17958
- const envValue = env[AWS_EC2_METADATA_V1_DISABLED];
17959
- fallbackBlockedFromProcessEnv = !!envValue && envValue !== "false";
17960
- if (envValue === undefined) {
18195
+ const envValue2 = env[AWS_EC2_METADATA_V1_DISABLED];
18196
+ fallbackBlockedFromProcessEnv = !!envValue2 && envValue2 !== "false";
18197
+ if (envValue2 === undefined) {
17961
18198
  throw new import_config6.CredentialsProviderError(`${AWS_EC2_METADATA_V1_DISABLED} not set in env, checking config file next.`, { logger: init.logger });
17962
18199
  }
17963
18200
  return fallbackBlockedFromProcessEnv;
@@ -18225,21 +18462,21 @@ var require_dist_cjs4 = __commonJS((exports) => {
18225
18462
  let sendBody = true;
18226
18463
  if (!externalAgent && expect === "100-continue") {
18227
18464
  sendBody = await Promise.race([
18228
- new Promise((resolve3) => {
18229
- timeoutId = Number(timing.setTimeout(() => resolve3(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
18465
+ new Promise((resolve4) => {
18466
+ timeoutId = Number(timing.setTimeout(() => resolve4(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
18230
18467
  }),
18231
- new Promise((resolve3) => {
18468
+ new Promise((resolve4) => {
18232
18469
  httpRequest2.on("continue", () => {
18233
18470
  timing.clearTimeout(timeoutId);
18234
- resolve3(true);
18471
+ resolve4(true);
18235
18472
  });
18236
18473
  httpRequest2.on("response", () => {
18237
18474
  timing.clearTimeout(timeoutId);
18238
- resolve3(false);
18475
+ resolve4(false);
18239
18476
  });
18240
18477
  httpRequest2.on("error", () => {
18241
18478
  timing.clearTimeout(timeoutId);
18242
- resolve3(false);
18479
+ resolve4(false);
18243
18480
  });
18244
18481
  })
18245
18482
  ]);
@@ -18314,13 +18551,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18314
18551
  return socketWarningTimestamp;
18315
18552
  }
18316
18553
  constructor(options) {
18317
- this.configProvider = new Promise((resolve3, reject) => {
18554
+ this.configProvider = new Promise((resolve4, reject) => {
18318
18555
  if (typeof options === "function") {
18319
18556
  options().then((_options) => {
18320
- resolve3(this.resolveDefaultConfig(_options));
18557
+ resolve4(this.resolveDefaultConfig(_options));
18321
18558
  }).catch(reject);
18322
18559
  } else {
18323
- resolve3(this.resolveDefaultConfig(options));
18560
+ resolve4(this.resolveDefaultConfig(options));
18324
18561
  }
18325
18562
  });
18326
18563
  }
@@ -18352,7 +18589,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18352
18589
  timing.clearTimeout(socketTimeoutId);
18353
18590
  timing.clearTimeout(keepAliveTimeoutId);
18354
18591
  };
18355
- const resolve3 = async (arg) => {
18592
+ const resolve4 = async (arg) => {
18356
18593
  await writeRequestBodyPromise;
18357
18594
  clearTimeouts();
18358
18595
  _resolve(arg);
@@ -18416,7 +18653,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18416
18653
  headers: getTransformedHeaders(res.headers),
18417
18654
  body: res
18418
18655
  });
18419
- resolve3({ response: httpResponse });
18656
+ resolve4({ response: httpResponse });
18420
18657
  });
18421
18658
  req.on("error", (err) => {
18422
18659
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -18748,13 +18985,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18748
18985
  return new NodeHttp2Handler(instanceOrOptions);
18749
18986
  }
18750
18987
  constructor(options) {
18751
- this.configProvider = new Promise((resolve3, reject) => {
18988
+ this.configProvider = new Promise((resolve4, reject) => {
18752
18989
  if (typeof options === "function") {
18753
18990
  options().then((opts) => {
18754
- resolve3(opts || {});
18991
+ resolve4(opts || {});
18755
18992
  }).catch(reject);
18756
18993
  } else {
18757
- resolve3(options || {});
18994
+ resolve4(options || {});
18758
18995
  }
18759
18996
  });
18760
18997
  }
@@ -18779,7 +19016,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18779
19016
  return new Promise((_resolve, _reject) => {
18780
19017
  let fulfilled = false;
18781
19018
  let writeRequestBodyPromise = undefined;
18782
- const resolve3 = async (arg) => {
19019
+ const resolve4 = async (arg) => {
18783
19020
  await writeRequestBodyPromise;
18784
19021
  _resolve(arg);
18785
19022
  };
@@ -18864,7 +19101,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18864
19101
  body: clientHttp2Stream
18865
19102
  });
18866
19103
  fulfilled = true;
18867
- resolve3({ response: httpResponse });
19104
+ resolve4({ response: httpResponse });
18868
19105
  if (useIsolatedSession) {
18869
19106
  session.close();
18870
19107
  }
@@ -18990,7 +19227,7 @@ var retryWrapper = (toRetry, maxRetries, delayMs) => {
18990
19227
  try {
18991
19228
  return await toRetry();
18992
19229
  } catch (e) {
18993
- await new Promise((resolve3) => setTimeout(resolve3, delayMs));
19230
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
18994
19231
  }
18995
19232
  }
18996
19233
  return await toRetry();
@@ -28282,8 +28519,8 @@ var require_signin = __commonJS((exports) => {
28282
28519
  // ../../node_modules/.bun/@aws-sdk+credential-provider-login@3.972.76/node_modules/@aws-sdk/credential-provider-login/dist-es/LoginCredentialsFetcher.js
28283
28520
  import { createHash as createHash2, createPrivateKey, createPublicKey, sign } from "crypto";
28284
28521
  import { promises as fs2 } from "fs";
28285
- import { homedir as homedir2 } from "os";
28286
- import { dirname as dirname3, join as join3 } from "path";
28522
+ import { homedir as homedir4 } from "os";
28523
+ import { dirname as dirname3, join as join5 } from "path";
28287
28524
  var import_config20, import_protocols3, LoginCredentialsFetcher;
28288
28525
  var init_LoginCredentialsFetcher = __esm(() => {
28289
28526
  import_config20 = __toESM(require_config(), 1);
@@ -28450,10 +28687,10 @@ var init_LoginCredentialsFetcher = __esm(() => {
28450
28687
  await fs2.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
28451
28688
  }
28452
28689
  getTokenFilePath() {
28453
- const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join3(homedir2(), ".aws", "login", "cache");
28690
+ const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join5(homedir4(), ".aws", "login", "cache");
28454
28691
  const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
28455
28692
  const loginSessionSha256 = createHash2("sha256").update(loginSessionBytes).digest("hex");
28456
- return join3(directory, `${loginSessionSha256}.json`);
28693
+ return join5(directory, `${loginSessionSha256}.json`);
28457
28694
  }
28458
28695
  derToRawSignature(derSignature) {
28459
28696
  let offset = 2;
@@ -38438,9 +38675,9 @@ __export(exports_config, {
38438
38675
  applyPurchaseProfile: () => applyPurchaseProfile
38439
38676
  });
38440
38677
  import { createHash as createHash3 } from "crypto";
38441
- import { copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
38442
- import { homedir as homedir3 } from "os";
38443
- import { dirname as dirname4, join as join4 } from "path";
38678
+ import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
38679
+ import { homedir as homedir5 } from "os";
38680
+ import { dirname as dirname4, join as join6 } from "path";
38444
38681
  function getPurchaseProfile() {
38445
38682
  return process.env["DOMAINS_PURCHASE_AWS_PROFILE"] ?? loadConfig4().purchase_aws_profile ?? undefined;
38446
38683
  }
@@ -38453,20 +38690,20 @@ function applyPurchaseProfile() {
38453
38690
  return profile;
38454
38691
  }
38455
38692
  function canonicalHome2(env) {
38456
- return env["HOME"] || env["USERPROFILE"] || homedir3();
38693
+ return env["HOME"] || env["USERPROFILE"] || homedir5();
38457
38694
  }
38458
38695
  function migrateLegacyConfig(env = process.env, dryRun = false) {
38459
38696
  const report = { dryRun, wouldCopy: false, copied: false };
38460
38697
  const home = canonicalHome2(env);
38461
- const canonicalDir = join4(home, ".hasna", "domains");
38462
- const newPath = join4(canonicalDir, "config.json");
38463
- if (existsSync2(newPath))
38698
+ const canonicalDir = join6(home, ".hasna", "domains");
38699
+ const newPath = join6(canonicalDir, "config.json");
38700
+ if (existsSync3(newPath))
38464
38701
  return report;
38465
- if (existsSync2(join4(canonicalDir, ".migrated-from-xdg-config.receipt.json")))
38702
+ if (existsSync3(join6(canonicalDir, ".migrated-from-xdg-config.receipt.json")))
38466
38703
  return report;
38467
- const xdgConfig = env["XDG_CONFIG_HOME"]?.trim() || join4(home, ".config");
38468
- const oldPath = join4(xdgConfig, "open-domains", "config.json");
38469
- if (!existsSync2(oldPath))
38704
+ const xdgConfig = env["XDG_CONFIG_HOME"]?.trim() || join6(home, ".config");
38705
+ const oldPath = join6(xdgConfig, "open-domains", "config.json");
38706
+ if (!existsSync3(oldPath))
38470
38707
  return report;
38471
38708
  report.wouldCopy = true;
38472
38709
  if (dryRun)
@@ -38478,7 +38715,7 @@ function migrateLegacyConfig(env = process.env, dryRun = false) {
38478
38715
  if (!oldBytes.equals(newBytes)) {
38479
38716
  throw new Error(`Refusing migration: copied ${newPath} does not byte-match ${oldPath}; the canonical config was not populated.`);
38480
38717
  }
38481
- writeFileSync2(join4(canonicalDir, ".migrated-from-xdg-config.receipt.json"), `${JSON.stringify({
38718
+ writeFileSync2(join6(canonicalDir, ".migrated-from-xdg-config.receipt.json"), `${JSON.stringify({
38482
38719
  migratedAt: new Date().toISOString(),
38483
38720
  from: oldPath,
38484
38721
  to: newPath,
@@ -38494,13 +38731,15 @@ function getConfigPath(env = process.env) {
38494
38731
  return env["DOMAINS_CONFIG_PATH"];
38495
38732
  const dir = env["DOMAINS_CONFIG_DIR"];
38496
38733
  if (dir)
38497
- return join4(dir, "config.json");
38498
- migrateLegacyConfig(env);
38499
- return join4(canonicalHome2(env), ".hasna", "domains", "config.json");
38734
+ return join6(dir, "config.json");
38735
+ if (!adoptResolverHome(resolverHome(env), env)) {
38736
+ migrateLegacyConfig(env);
38737
+ }
38738
+ return getDefaultConfigPath(env);
38500
38739
  }
38501
38740
  function loadConfig4(env = process.env) {
38502
38741
  const path = getConfigPath(env);
38503
- if (!existsSync2(path))
38742
+ if (!existsSync3(path))
38504
38743
  return {};
38505
38744
  try {
38506
38745
  return JSON.parse(readFileSync5(path, "utf-8"));
@@ -38511,7 +38750,7 @@ function loadConfig4(env = process.env) {
38511
38750
  function saveConfig(config, env = process.env) {
38512
38751
  const path = getConfigPath(env);
38513
38752
  const dir = dirname4(path);
38514
- if (!existsSync2(dir))
38753
+ if (!existsSync3(dir))
38515
38754
  mkdirSync2(dir, { recursive: true });
38516
38755
  writeFileSync2(path, JSON.stringify(config, null, 2), "utf-8");
38517
38756
  }
@@ -38560,7 +38799,9 @@ function getConfigKey(keyPath) {
38560
38799
  }
38561
38800
  return;
38562
38801
  }
38563
- var init_config = () => {};
38802
+ var init_config = __esm(() => {
38803
+ init_app_home();
38804
+ });
38564
38805
 
38565
38806
  // src/lib/compact-output.ts
38566
38807
  function parseLimit(value, fallback = DEFAULT_LIST_LIMIT, maxLimit = MAX_LIST_LIMIT) {
@@ -41357,9 +41598,9 @@ __export(exports_commander, {
41357
41598
  });
41358
41599
  import { chmod, mkdir, readFile, rename, writeFile as writeFile2 } from "fs/promises";
41359
41600
  import { Buffer as Buffer2 } from "buffer";
41360
- import { existsSync as existsSync4 } from "fs";
41361
- import { homedir as homedir5 } from "os";
41362
- import { join as join6 } from "path";
41601
+ import { existsSync as existsSync5 } from "fs";
41602
+ import { homedir as homedir7 } from "os";
41603
+ import { join as join8 } from "path";
41363
41604
  import { createHmac, timingSafeEqual } from "crypto";
41364
41605
  import { lookup as dnsLookup } from "dns/promises";
41365
41606
  import { isIP as isIP2 } from "net";
@@ -41464,7 +41705,7 @@ function channelMatchesEvent(channel, event) {
41464
41705
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
41465
41706
  }
41466
41707
  function getEventsDataDir(override) {
41467
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join6(homedir5(), ".hasna", "events");
41708
+ return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join8(homedir7(), ".hasna", "events");
41468
41709
  }
41469
41710
  function getActiveEventsDirEnv() {
41470
41711
  if (process.env[HASNA_EVENTS_DIR_ENV])
@@ -41480,12 +41721,12 @@ class JsonEventsStore {
41480
41721
  channelsPath;
41481
41722
  eventsPath;
41482
41723
  deliveriesPath;
41483
- constructor(dataDir = getEventsDataDir()) {
41484
- this.dataDir = dataDir;
41485
- this.runtime = localJsonRuntime(dataDir);
41486
- this.channelsPath = join6(dataDir, "channels.json");
41487
- this.eventsPath = join6(dataDir, "events.json");
41488
- this.deliveriesPath = join6(dataDir, "deliveries.json");
41724
+ constructor(dataDir2 = getEventsDataDir()) {
41725
+ this.dataDir = dataDir2;
41726
+ this.runtime = localJsonRuntime(dataDir2);
41727
+ this.channelsPath = join8(dataDir2, "channels.json");
41728
+ this.eventsPath = join8(dataDir2, "events.json");
41729
+ this.deliveriesPath = join8(dataDir2, "deliveries.json");
41489
41730
  }
41490
41731
  async init() {
41491
41732
  await mkdir(this.dataDir, { recursive: true, mode: 448 });
@@ -41602,7 +41843,7 @@ class JsonEventsStore {
41602
41843
  };
41603
41844
  }
41604
41845
  async ensureArrayFile(path) {
41605
- if (!existsSync4(path)) {
41846
+ if (!existsSync5(path)) {
41606
41847
  await writeFile2(path, `[]
41607
41848
  `, { encoding: "utf-8", mode: 384 });
41608
41849
  }
@@ -41632,7 +41873,7 @@ class JsonEventsStore {
41632
41873
  });
41633
41874
  }
41634
41875
  }
41635
- function localJsonRuntime(dataDir = getEventsDataDir()) {
41876
+ function localJsonRuntime(dataDir2 = getEventsDataDir()) {
41636
41877
  return {
41637
41878
  mode: "local-files",
41638
41879
  name: "json-events-store",
@@ -41645,7 +41886,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
41645
41886
  durable: true,
41646
41887
  idempotency: "best-effort-local",
41647
41888
  replayCursors: true,
41648
- description: `Local JSON files in ${dataDir}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
41889
+ description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
41649
41890
  };
41650
41891
  }
41651
41892
  function encodeLocalJsonEventCursor(offset, options = {}) {
@@ -41709,8 +41950,8 @@ function assertCursorFilter(name, cursorValue, optionValue) {
41709
41950
  function findEventByIdentity(events, identity2) {
41710
41951
  return events.find((event) => identity2.id !== undefined && event.id === identity2.id || identity2.dedupeKey !== undefined && event.dedupeKey === identity2.dedupeKey);
41711
41952
  }
41712
- async function getEventsStatus(dataDir) {
41713
- const store = new JsonEventsStore(dataDir);
41953
+ async function getEventsStatus(dataDir2) {
41954
+ const store = new JsonEventsStore(dataDir2);
41714
41955
  await store.init();
41715
41956
  const [channels, events, deliveries] = await Promise.all([
41716
41957
  store.listChannels(),
@@ -41752,9 +41993,9 @@ async function getEventsStatus(dataDir) {
41752
41993
  }
41753
41994
  };
41754
41995
  }
41755
- function statusFile(dataDir, fileName, records) {
41756
- const path = join6(dataDir, fileName);
41757
- return { path, exists: existsSync4(path), records };
41996
+ function statusFile(dataDir2, fileName, records) {
41997
+ const path = join8(dataDir2, fileName);
41998
+ return { path, exists: existsSync5(path), records };
41758
41999
  }
41759
42000
  function buildSignatureBase(timestamp, body) {
41760
42001
  return `${timestamp}.${body}`;
@@ -42055,7 +42296,7 @@ async function pinnedNativeRequest(target, addresses, method, headers, body, sig
42055
42296
  callback(null, entries);
42056
42297
  }
42057
42298
  };
42058
- return new Promise((resolve3, reject) => {
42299
+ return new Promise((resolve4, reject) => {
42059
42300
  const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
42060
42301
  const onAbort = () => {
42061
42302
  const error = new Error("The operation was aborted.");
@@ -42082,7 +42323,7 @@ async function pinnedNativeRequest(target, addresses, method, headers, body, sig
42082
42323
  else if (Array.isArray(value))
42083
42324
  headersRecord[name] = value.join(", ");
42084
42325
  }
42085
- resolve3(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
42326
+ resolve4(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
42086
42327
  });
42087
42328
  }
42088
42329
  });
@@ -42179,7 +42420,7 @@ async function dispatchCommand(event, channel) {
42179
42420
  HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
42180
42421
  HASNA_EVENT_JSON: eventJson
42181
42422
  };
42182
- return new Promise((resolve3) => {
42423
+ return new Promise((resolve4) => {
42183
42424
  const child = spawn(channel.command.command, channel.command.args ?? [], {
42184
42425
  cwd: channel.command.cwd,
42185
42426
  env,
@@ -42197,7 +42438,7 @@ async function dispatchCommand(event, channel) {
42197
42438
  });
42198
42439
  child.on("error", (error) => {
42199
42440
  clearTimeout(timeout);
42200
- resolve3({
42441
+ resolve4({
42201
42442
  attempt: 1,
42202
42443
  status: "failed",
42203
42444
  startedAt,
@@ -42210,7 +42451,7 @@ async function dispatchCommand(event, channel) {
42210
42451
  child.on("close", (code, signal) => {
42211
42452
  clearTimeout(timeout);
42212
42453
  const success = code === 0;
42213
- resolve3({
42454
+ resolve4({
42214
42455
  attempt: 1,
42215
42456
  status: success ? "success" : "failed",
42216
42457
  startedAt,
@@ -45577,15 +45818,15 @@ ${"\u2500".repeat(45)}`);
45577
45818
 
45578
45819
  // src/cli/commands/mcp-install.ts
45579
45820
  init_stdout();
45580
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
45581
- import { homedir as homedir4 } from "os";
45582
- import { dirname as dirname5, join as join5 } from "path";
45821
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
45822
+ import { homedir as homedir6 } from "os";
45823
+ import { dirname as dirname5, join as join7 } from "path";
45583
45824
  import { execSync as execSync2 } from "child_process";
45584
45825
  var MCP_SERVER_NAME = "domains";
45585
45826
  function getClaudeConfigPaths() {
45586
45827
  return {
45587
- global: join5(homedir4(), ".claude", "claude_desktop_config.json"),
45588
- project: join5(process.cwd(), ".claude", "settings.json")
45828
+ global: join7(homedir6(), ".claude", "claude_desktop_config.json"),
45829
+ project: join7(process.cwd(), ".claude", "settings.json")
45589
45830
  };
45590
45831
  }
45591
45832
  function getMcpBinaryPath() {
@@ -45597,12 +45838,12 @@ function getMcpBinaryPath() {
45597
45838
  }
45598
45839
  function ensureConfigDir(configPath) {
45599
45840
  const dir = dirname5(configPath);
45600
- if (!existsSync3(dir)) {
45841
+ if (!existsSync4(dir)) {
45601
45842
  mkdirSync3(dir, { recursive: true });
45602
45843
  }
45603
45844
  }
45604
45845
  function readConfig(configPath) {
45605
- if (!existsSync3(configPath))
45846
+ if (!existsSync4(configPath))
45606
45847
  return {};
45607
45848
  try {
45608
45849
  return JSON.parse(readFileSync7(configPath, "utf-8"));
@@ -45631,7 +45872,7 @@ function registerMcpCommand(program2) {
45631
45872
  mcp.command("uninstall").description("Remove domains MCP server from Claude Code config").option("--project", "Remove from project config instead of global").action((opts) => {
45632
45873
  const paths = getClaudeConfigPaths();
45633
45874
  const configPath = opts.project ? paths.project : paths.global;
45634
- if (!existsSync3(configPath)) {
45875
+ if (!existsSync4(configPath)) {
45635
45876
  printLine("Config file not found \u2014 nothing to remove.");
45636
45877
  return;
45637
45878
  }
@@ -45649,7 +45890,7 @@ function registerMcpCommand(program2) {
45649
45890
  const paths = getClaudeConfigPaths();
45650
45891
  const status = [];
45651
45892
  for (const [scope, configPath] of [["global", paths.global], ["project", paths.project]]) {
45652
- if (!existsSync3(configPath)) {
45893
+ if (!existsSync4(configPath)) {
45653
45894
  status.push({ scope, config_path: configPath, exists: false, registered: false });
45654
45895
  continue;
45655
45896
  }
@@ -46287,6 +46528,20 @@ var PG_MIGRATIONS = [
46287
46528
  var OWNER_DSN_ENV = "HASNA_DOMAINS_DATABASE_URL_OWNER";
46288
46529
  var APP_DSN_ENV = "HASNA_DOMAINS_DATABASE_URL";
46289
46530
  var LEGACY_DSN_ENV = "DATABASE_URL";
46531
+ var ACKNOWLEDGED_LEGACY_MIGRATION_IDS = [
46532
+ "domains_apikeys_tenancy_0001",
46533
+ "domains_apikeys_tenancy_0002",
46534
+ "domains_tenancy_0001",
46535
+ "domains_tenancy_0002",
46536
+ "domains_tenancy_0003",
46537
+ "domains_tenancy_0004",
46538
+ "domains_tenancy_0005",
46539
+ "domains_tenancy_0006",
46540
+ "domains_tenancy_0007",
46541
+ "domains_tenancy_0008",
46542
+ "domains_tenancy_0009",
46543
+ "domains_tenancy_0010"
46544
+ ];
46290
46545
  function buildMigrations() {
46291
46546
  const migrations2 = [];
46292
46547
  PG_MIGRATIONS.forEach((sql, i4) => {
@@ -46312,7 +46567,7 @@ async function runMigrations(opts = {}) {
46312
46567
  try {
46313
46568
  const client = wrapExecutor(pool2);
46314
46569
  const ledger = new MigrationLedger(client, buildMigrations(), {
46315
- acknowledgedLegacyIds: ["domains_apikeys_tenancy_0001"]
46570
+ acknowledgedLegacyIds: ACKNOWLEDGED_LEGACY_MIGRATION_IDS
46316
46571
  });
46317
46572
  return await ledger.migrate(opts.dryRun ? { dryRun: true } : {});
46318
46573
  } finally {
@@ -47223,13 +47478,13 @@ async function loadRdapBootstrap(path) {
47223
47478
  return map;
47224
47479
  }
47225
47480
  function whoisRaw(server, query2, timeoutMs = 25000) {
47226
- return new Promise((resolve3) => {
47481
+ return new Promise((resolve4) => {
47227
47482
  const chunks = [];
47228
47483
  let settled = false;
47229
47484
  const done = (r4) => {
47230
47485
  if (!settled) {
47231
47486
  settled = true;
47232
- resolve3(r4);
47487
+ resolve4(r4);
47233
47488
  }
47234
47489
  };
47235
47490
  const sock = net.createConnection({ host: server, port: 43 });