@hasna/domains 0.0.47 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +58 -34
  2. package/dist/cli/commands/dns.d.ts.map +1 -1
  3. package/dist/cli/commands/doctor.d.ts.map +1 -1
  4. package/dist/cli/commands/serve.d.ts +1 -0
  5. package/dist/cli/commands/serve.d.ts.map +1 -1
  6. package/dist/cli/index.js +4754 -2105
  7. package/dist/db/database.d.ts +6 -23
  8. package/dist/db/database.d.ts.map +1 -1
  9. package/dist/db/domains.d.ts +3 -14
  10. package/dist/db/domains.d.ts.map +1 -1
  11. package/dist/db/store.d.ts +36 -32
  12. package/dist/db/store.d.ts.map +1 -1
  13. package/dist/generated/storage-kit/backend.d.ts +4 -4
  14. package/dist/generated/storage-kit/backend.d.ts.map +1 -1
  15. package/dist/generated/storage-kit/index.d.ts +1 -1
  16. package/dist/generated/storage-kit/index.d.ts.map +1 -1
  17. package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
  18. package/dist/generated/storage-kit/pool.d.ts +2 -5
  19. package/dist/generated/storage-kit/pool.d.ts.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +1127 -1734
  23. package/dist/lib/app-home.d.ts +32 -44
  24. package/dist/lib/app-home.d.ts.map +1 -1
  25. package/dist/lib/client-storage-policy.d.ts +10 -0
  26. package/dist/lib/client-storage-policy.d.ts.map +1 -0
  27. package/dist/lib/client-types.d.ts +184 -0
  28. package/dist/lib/client-types.d.ts.map +1 -0
  29. package/dist/lib/cloudflare.d.ts.map +1 -1
  30. package/dist/lib/cloudflare.js +23 -0
  31. package/dist/lib/config.d.ts +6 -16
  32. package/dist/lib/config.d.ts.map +1 -1
  33. package/dist/lib/dns-plan.d.ts +1 -1
  34. package/dist/lib/dns-plan.d.ts.map +1 -1
  35. package/dist/lib/domains-resolver.d.ts +96 -0
  36. package/dist/lib/domains-resolver.d.ts.map +1 -0
  37. package/dist/lib/registrar.d.ts +8 -0
  38. package/dist/lib/registrar.d.ts.map +1 -1
  39. package/dist/lib/registrar.js +23 -0
  40. package/dist/mcp/harness.d.ts +46 -0
  41. package/dist/mcp/harness.d.ts.map +1 -0
  42. package/dist/mcp/http.d.ts +3 -2
  43. package/dist/mcp/http.d.ts.map +1 -1
  44. package/dist/mcp/index.d.ts.map +1 -1
  45. package/dist/mcp/index.js +24162 -25378
  46. package/dist/mcp/tool-filter.d.ts +6 -0
  47. package/dist/mcp/tool-filter.d.ts.map +1 -1
  48. package/dist/sdk/index.d.ts +21 -10
  49. package/dist/sdk/index.d.ts.map +1 -1
  50. package/dist/sdk/index.js +813 -275
  51. package/dist/server/index.d.ts +6 -0
  52. package/dist/server/index.d.ts.map +1 -1
  53. package/dist/server/index.js +84 -29
  54. package/package.json +5 -7
  55. package/postinstall.js +13 -14
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hasna/domains
2
2
 
3
- Domain portfolio, registrar, marketplace, and DNS management for AI agents. The package ships a CLI, MCP server, authenticated HTTP API, generated SDK, and library exports. CLI workflows use local SQLite by default and can use the shared HTTP API in cloud mode; `domains-serve` connects directly to cloud Postgres.
3
+ Domain portfolio, registrar, marketplace, and DNS management for AI agents. The package ships a CLI, MCP server, authenticated HTTP API, generated SDK, and library exports. Every client surface resolves its credential and authority through the one shared `@hasna/contracts` resolver (macOS Keychain, `~/.hasna/domains/config/credentials`, or `HASNA_DOMAINS_API_KEY`, with the fleet gateway `https://api.hasna.com/domains` as the default authority), and data commands fail closed when no credential resolves: local SQLite path settings are rejected; `domains-serve` connects directly to cloud Postgres.
4
4
 
5
5
  ## Features
6
6
 
@@ -33,7 +33,7 @@ Domain portfolio, registrar, marketplace, and DNS management for AI agents. The
33
33
  npm install -g @hasna/domains
34
34
  ```
35
35
 
36
- Data is stored in the local domains data directory. The home is resolved through `@hasna/paths` (XDG / macOS home layout, honoring `HASNA_*_HOME` overrides). The legacy `~/.hasna/domains` default stays the effective home until the XDG data home is adopted — the operator sets `HASNA_DATA_HOME`, or the store is physically migrated there (`domains.db` exists at the resolver home) so an existing local store never becomes invisible on upgrade. `HASNA_DOMAINS_HOME` / `DOMAINS_HOME` / `HASNA_DOMAINS_DIR` / `DOMAINS_DIR` are exact-app overrides that win unconditionally; override the db file itself with `DOMAINS_DB_PATH` / `HASNA_DOMAINS_DB_PATH`.
36
+ All normal clients use the shared account API. Saved credentials live in the macOS Keychain or `~/.hasna/domains/config/credentials`; `HASNA_HOME` and `HASNA_CONFIG_HOME` can select the credential root. Existing SQLite files are preserved for verified migration and are never opened by the CLI, MCP or SDK factory.
37
37
 
38
38
  ## Optional Command Groups
39
39
 
@@ -232,14 +232,21 @@ Route 53 sync imports registered domains when the selected AWS account permits `
232
232
 
233
233
  ## Storage
234
234
 
235
- The CLI and library use local SQLite by default. The client selects the hosted HTTP API when both `HASNA_DOMAINS_API_URL` and `HASNA_DOMAINS_API_KEY` are set a database DSN is never exposed to clients.
235
+ Every client surface the CLI, the MCP server and the `./sdk` resolves its credential and authority through the ONE shared `@hasna/contracts` resolver, fresh on every call:
236
236
 
237
- ```bash
238
- export HASNA_DOMAINS_API_URL=https://domains.example.com
239
- export HASNA_DOMAINS_API_KEY=dom_...
240
- ```
237
+ 1. an explicit `--api-key` / `--profile` argument (code-level)
238
+ 2. a deliberate env pointer — `HASNA_DOMAINS_API_KEY_OVERRIDE`, `HASNA_PROFILE`, `HASNA_DOMAINS_API_KEY_REF`
239
+ 3. the macOS Keychain — item `hasna.credentials.domains.api-key` / `.api-url`, account `HASNA_STATION`, else the short hostname, else `$USER`
240
+ 4. disk, read at call time — `~/.hasna/domains/config/credentials` (owner-only 0600; `HASNA_HOME` / `HASNA_CONFIG_HOME` override the root)
241
+ 5. `HASNA_DOMAINS_API_KEY` in the process env — a legitimate tier
242
+
243
+ The authority follows the same ladder — `HASNA_DOMAINS_API_URL`, the Keychain `api-url` item, the credentials file — and **defaults to the fleet gateway `https://api.hasna.com/domains`** once a credential resolves, so a key alone is a complete configuration. The unprefixed `DOMAINS_API_URL` / `DOMAINS_API_KEY` aliases are accepted by the resolver for one release; the canonical `HASNA_DOMAINS_*` names always win. Retired locations (`~/.hasna/fleet-env`, the cloud dirs under `~/.hasna`, `~/.config/hasna`, `$XDG_CONFIG_HOME`) are never read, and no `*_MODE` / `*_STORAGE_MODE` variable selects anything.
241
244
 
242
- The unprefixed `DOMAINS_API_URL` and `DOMAINS_API_KEY` aliases are also accepted. When only one of URL and key is set, the client refuses to start (fail-closed). The standalone `domains-serve` process is the server side: it connects directly to PostgreSQL using `HASNA_DOMAINS_DATABASE_URL` (SQLite when unset) and requires `HASNA_DOMAINS_API_SIGNING_KEY`. Apply owner-role migrations first with `domains db migrate`.
245
+ **Fail closed.** A hosted run with no credential exits non-zero naming the canonical env pair never a silent fallback to SQLite, never a `*-local-fallback` event. A database DSN is never exposed to clients.
246
+
247
+ **SQLite client selection is retired.** Unset `HASNA_DOMAINS_DB_PATH`, `DOMAINS_DB_PATH`, `HASNA_DOMAINS_DIR` and `DOMAINS_DIR` before using normal clients. These settings are rejected even when no API key is configured. Preserve existing databases until all records have been reconciled and verified in the shared account; removing a path setting does not migrate data.
248
+
249
+ `domains serve` and `domains-serve` start the same authenticated PostgreSQL service. Both require a server database DSN (`HASNA_DOMAINS_DATABASE_URL`) and signing key (`HASNA_DOMAINS_API_SIGNING_KEY`); a client API key cannot authorize a listener. Data routes use `/v1` and validate each caller's key and revocation state. Apply owner-role migrations first with `domains db migrate`.
243
250
 
244
251
  ## MCP Server
245
252
 
@@ -297,10 +304,12 @@ Safe mode registers only read-only/list/check/export tools. Mutating tools such
297
304
  ```bash
298
305
  domains-serve --host 0.0.0.0 --port 8080
299
306
  curl http://127.0.0.1:8080/health
300
- curl -H "x-api-key: $DOMAINS_API_KEY" http://127.0.0.1:8080/v1/domains
307
+ curl -H "x-api-key: $HASNA_DOMAINS_API_KEY" http://127.0.0.1:8080/v1/domains
301
308
  ```
302
309
 
303
- The package also exports the generated client:
310
+ The package also exports the generated client, wired to the same shared
311
+ resolver the CLI and MCP server use — fresh on every request, so a key rotation
312
+ heals a long-lived client:
304
313
 
305
314
  ```ts
306
315
  import { createDomainsClientFromEnv } from "@hasna/domains/sdk";
@@ -309,25 +318,34 @@ const domains = createDomainsClientFromEnv();
309
318
  const portfolio = await domains.listDomains({ status: "active" });
310
319
  ```
311
320
 
312
- `domains serve` is a separate, unauthenticated local-development server over the local store. Use `domains-serve` for the cloud Postgres API.
321
+ An explicit `baseUrl` with no `apiKey` builds a client pinned to that authority
322
+ that never picks up an ambient fleet key; without a resolvable credential the
323
+ SDK throws — it never degrades to an anonymous client or to local data.
324
+
325
+ `domains serve` is an alias for the authenticated server runtime, preserving its CLI host/port defaults. Its account data routes are `/v1/*`; the former unauthenticated `/domains` proxy has been removed.
313
326
 
314
327
  ## Environment Variables
315
328
 
316
329
  | Variable | Description |
317
330
  |----------|-------------|
318
- | `DOMAINS_DB_PATH` | Override database file path |
319
- | `HASNA_DOMAINS_DB_PATH` | Override database file path |
320
- | `DOMAINS_CONFIG_PATH` | Override config file path |
321
- | `DOMAINS_CONFIG_DIR` | Override config directory |
322
- | `HASNA_DOMAINS_DIR` | Override database directory |
323
- | `DOMAINS_DIR` | Override database directory fallback |
331
+ | `HASNA_DOMAINS_API_KEY` | Hosted API key (canonical env tier of the shared resolver; below the Keychain and the credential file) |
332
+ | `HASNA_DOMAINS_API_URL` | Optional hosted API base URL — defaults to the fleet gateway `https://api.hasna.com/domains` once a key resolves |
333
+ | `HASNA_DOMAINS_API_KEY_OVERRIDE` | Deliberate per-run key override that outranks every other tier |
334
+ | `HASNA_DOMAINS_API_KEY_REF` | Deliberate secrets-vault pointer resolved through the `@hasna/secrets` SDK at request time |
335
+ | `HASNA_PROFILE` | Global identity profile pointer (`credentials-<profile>` beside the credential file) |
336
+ | `HASNA_HOME` | Shared root override `<HASNA_HOME>/domains/` for local data, `<HASNA_HOME>/domains/config/credentials` for the credential file |
337
+ | `HASNA_CONFIG_HOME` | Config-root override for the resolver's credential file |
338
+ | `HASNA_DOMAINS_DB_PATH` | Retired client setting; migrate and verify existing data before removal |
339
+ | `DOMAINS_DB_PATH` | Retired legacy client setting; rejected |
340
+ | `HASNA_DOMAINS_DIR` | Retired client setting; rejected |
341
+ | `DOMAINS_DIR` | Retired legacy client setting; rejected |
342
+ | `HASNA_DOMAINS_HOME`, `DOMAINS_HOME` | Exact-app home overrides (canonical name wins over the alias) |
343
+ | `HASNA_DOMAINS_CONFIG_PATH`, `DOMAINS_CONFIG_PATH` | Override the settings config file path |
344
+ | `DOMAINS_CONFIG_DIR` | Override the settings config directory |
324
345
  | `DOMAINS_COMMAND_GROUPS` | Comma-separated optional command groups to load, or `all` |
325
346
  | `DOMAINS_ENABLE_EXTRAS` | Set to `1` to load all optional command groups |
326
347
  | `DOMAINS_MCP_SAFE_MODE` | Set to `1` to expose only read-only MCP tools |
327
- | `HASNA_DOMAINS_API_URL`, `DOMAINS_API_URL` | Hosted HTTP API base URL for the CLI/library store (set together with the key) |
328
- | `HASNA_DOMAINS_API_KEY`, `DOMAINS_API_KEY` | Hosted HTTP API key for the CLI/library store and SDK (set together with the URL) |
329
- | `HASNA_DOMAINS_ALLOW_CLOUD_WITH_LOCAL_PATH` | Set to `1` to keep the hosted store even though a local path variable is set. Without it that combination is a hard error — see below |
330
- | `HASNA_DOMAINS_DATABASE_URL` | Server-side PostgreSQL DSN used by `domains-serve` and DB migrations; SQLite backend when unset |
348
+ | `HASNA_DOMAINS_DATABASE_URL` | Server-side PostgreSQL DSN used by `domains-serve` and DB migrations; required for server storage |
331
349
  | `HASNA_DOMAINS_API_SIGNING_KEY` | HMAC signing secret used by `domains-serve` to verify API keys |
332
350
  | `AWS_PROFILE` | AWS profile for Route 53 Domains and hosted zones |
333
351
  | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` | AWS credential fallback |
@@ -344,27 +362,33 @@ const portfolio = await domains.listDomains({ status: "active" });
344
362
  | `BRANDSIGHT_DEMO_STUBS`, `BRANDSIGHT_ALLOW_STUBS` | Set either to `1` to allow demo stub responses when the Brandsight API is unreachable |
345
363
  | `SEDO_PARTNER_ID`, `SEDO_API_KEY`, `SEDO_USERNAME`, `SEDO_PASSWORD` | Sedo marketplace API credentials |
346
364
 
347
- ### Picking a store: a local path and cloud credentials are mutually exclusive
365
+ ### Picking a store: a local path and a configured credential are mutually exclusive
348
366
 
349
- `DOMAINS_DB_PATH`, `HASNA_DOMAINS_DB_PATH`, `DOMAINS_DIR` and `HASNA_DOMAINS_DIR` all name a
350
- **local sqlite file**. Only the local store has one. So setting any of them while
351
- `HASNA_DOMAINS_API_URL` + `HASNA_DOMAINS_API_KEY` are also set asks for two different stores at
352
- once, and `getStore()` **refuses to start** rather than pick one for you.
367
+ `HASNA_DOMAINS_DB_PATH`, `DOMAINS_DB_PATH`, `HASNA_DOMAINS_DIR`, `DOMAINS_DIR` and
368
+ `HASNA_DOMAINS_HOME` all name a **local sqlite file or directory**. Only the local store
369
+ has one. So setting any of them while the environment also configures a hosted
370
+ authority or credential (`HASNA_DOMAINS_API_URL`, `HASNA_DOMAINS_API_KEY`, the
371
+ deliberate pointers, `HASNA_PROFILE`, or a Keychain / credential-file entry)
372
+ asks for two different stores at once, and **`getStore()` refuses to start**
373
+ rather than pick one for you. Local mode applies only when the environment
374
+ configures nothing at all.
353
375
 
354
- This is deliberate. Before it, the combination silently resolved to the cloud store: a script
355
- that set `DOMAINS_DB_PATH` created no sqlite file, wrote to the remote portfolio, and printed
356
- success. Nothing on any surface said which store it had used.
376
+ This is deliberate. Before it, the combination silently resolved to the cloud
377
+ store: a script that set `DOMAINS_DB_PATH` created no sqlite file, wrote to the
378
+ remote portfolio, and printed success. Nothing on any surface said which store
379
+ it had used.
357
380
 
358
381
  To resolve it, say which you meant:
359
382
 
360
383
  ```sh
361
- unset HASNA_DOMAINS_API_URL HASNA_DOMAINS_API_KEY # use the sqlite file the path variable names
362
- unset DOMAINS_DB_PATH # use the hosted store
363
- HASNA_DOMAINS_ALLOW_CLOUD_WITH_LOCAL_PATH=1 # keep the hosted store with the variable present
384
+ unset HASNA_DOMAINS_DB_PATH DOMAINS_DB_PATH HASNA_DOMAINS_DIR DOMAINS_DIR HASNA_DOMAINS_HOME # use the hosted store
385
+ unset HASNA_DOMAINS_API_URL HASNA_DOMAINS_API_KEY HASNA_DOMAINS_API_KEY_OVERRIDE HASNA_DOMAINS_API_KEY_REF HASNA_PROFILE # use the sqlite file the path variable names
364
386
  ```
365
387
 
366
- `domains doctor` names the store it resolved, in its `Store` section, before any other check
367
- runs. Run it whenever you are unsure which dataset a command is about to touch.
388
+ `domains doctor` names the store it resolved, in its `Store` section including
389
+ where the URL and key came from and which tier supplied the key before any
390
+ other check runs. Run it whenever you are unsure which dataset a command is
391
+ about to touch.
368
392
 
369
393
  ## License
370
394
 
@@ -1 +1 @@
1
- {"version":3,"file":"dns.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAa1E,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,aAA4D,CAAC;AAE7F;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACjE,OAAO,EAAE,CAAC,EAAE,GACX;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAW7C;AAyBD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,CAAA;CAAO,GAC5D,IAAI,CAsYN"}
1
+ {"version":3,"file":"dns.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAa1E,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,aAA4D,CAAC;AAE7F;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACjE,OAAO,EAAE,CAAC,EAAE,GACX;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAW7C;AAyBD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,CAAA;CAAO,GAC5D,IAAI,CA4ZN"}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2I5D"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuI5D"}
@@ -1,3 +1,4 @@
1
1
  import type { Command } from "commander";
2
+ /** Run the canonical authenticated service, never an account-key proxy. */
2
3
  export declare function registerServeCommand(program: Command): void;
3
4
  //# sourceMappingURL=serve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuG3D"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAS3D"}