@hasna/domains 0.0.46 → 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.
- package/README.md +58 -34
- package/dist/cli/commands/dns.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts +1 -0
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/index.js +4946 -2042
- package/dist/db/database.d.ts +6 -21
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/domains.d.ts +3 -14
- package/dist/db/domains.d.ts.map +1 -1
- package/dist/db/store.d.ts +36 -32
- package/dist/db/store.d.ts.map +1 -1
- package/dist/generated/storage-kit/backend.d.ts +4 -4
- package/dist/generated/storage-kit/backend.d.ts.map +1 -1
- package/dist/generated/storage-kit/index.d.ts +1 -1
- package/dist/generated/storage-kit/index.d.ts.map +1 -1
- package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
- package/dist/generated/storage-kit/pool.d.ts +2 -5
- package/dist/generated/storage-kit/pool.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1268 -1639
- package/dist/lib/app-home.d.ts +48 -0
- package/dist/lib/app-home.d.ts.map +1 -0
- package/dist/lib/client-storage-policy.d.ts +10 -0
- package/dist/lib/client-storage-policy.d.ts.map +1 -0
- package/dist/lib/client-types.d.ts +184 -0
- package/dist/lib/client-types.d.ts.map +1 -0
- package/dist/lib/cloudflare.d.ts.map +1 -1
- package/dist/lib/cloudflare.js +23 -0
- package/dist/lib/config.d.ts +8 -17
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/dns-plan.d.ts +1 -1
- package/dist/lib/dns-plan.d.ts.map +1 -1
- package/dist/lib/domains-resolver.d.ts +96 -0
- package/dist/lib/domains-resolver.d.ts.map +1 -0
- package/dist/lib/registrar.d.ts +8 -0
- package/dist/lib/registrar.d.ts.map +1 -1
- package/dist/lib/registrar.js +23 -0
- package/dist/mcp/harness.d.ts +46 -0
- package/dist/mcp/harness.d.ts.map +1 -0
- package/dist/mcp/http.d.ts +3 -2
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +23611 -24591
- package/dist/mcp/tool-filter.d.ts +6 -0
- package/dist/mcp/tool-filter.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +21 -10
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +861 -245
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +84 -29
- package/dist/server/migrations.d.ts +35 -0
- package/dist/server/migrations.d.ts.map +1 -1
- package/package.json +8 -8
- package/postinstall.js +41 -0
package/dist/server/index.d.ts
CHANGED
|
@@ -15,4 +15,10 @@ export declare const SIGNING_KEY_ENVS: readonly ["HASNA_DOMAINS_API_SIGNING_KEY"
|
|
|
15
15
|
/** Normalize the module-injected env names to the kit/auth conventions. */
|
|
16
16
|
export declare function normalizeEnv(env?: NodeJS.ProcessEnv): void;
|
|
17
17
|
export declare function resolveSigningSecret(env?: NodeJS.ProcessEnv): string;
|
|
18
|
+
export declare const USAGE = "domains-serve \u2014 standalone HTTP API server for @hasna/domains (PostgreSQL backend)\n\nUsage: domains-serve [--port <n>] [--host <addr>]\n\nOptions:\n --port <n> Port to listen on (default: $PORT or 8080)\n --host <addr> Address to bind (default: $HOST or 0.0.0.0)\n -h, --help Print this help and exit\n -V, --version Print the package version and exit\n\nEnvironment:\n HASNA_DOMAINS_DATABASE_URL PostgreSQL DSN (falls back to DATABASE_URL)\n HASNA_DOMAINS_API_SIGNING_KEY HMAC signing secret for API keys\n (falls back to API_KEY_SIGNING_SECRET)";
|
|
19
|
+
/** Shared authenticated server for both domains serve and domains-serve. */
|
|
20
|
+
export declare function startDomainsServer(options: {
|
|
21
|
+
port: number;
|
|
22
|
+
host: string;
|
|
23
|
+
}): Promise<void>;
|
|
18
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AASH,eAAO,MAAM,gBAAgB,+FAInB,CAAC;AAEX,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAIvE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAQjF"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AASH,eAAO,MAAM,gBAAgB,+FAInB,CAAC;AAEX,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAIvE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAQjF;AAUD,eAAO,MAAM,KAAK,0mBAasD,CAAC;AAwBzE,4EAA4E;AAC5E,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgD/F"}
|
package/dist/server/index.js
CHANGED
|
@@ -79,7 +79,7 @@ function viewWindow(view) {
|
|
|
79
79
|
}
|
|
80
80
|
function toBuffer(secret) {
|
|
81
81
|
if (typeof secret === "string")
|
|
82
|
-
return Buffer.from(secret, "utf8");
|
|
82
|
+
return Buffer.from(secret.trim(), "utf8");
|
|
83
83
|
if (ArrayBuffer.isView(secret)) {
|
|
84
84
|
const [store, byteOffset, byteLength] = viewWindow(secret);
|
|
85
85
|
return Buffer.from(store, byteOffset, byteLength);
|
|
@@ -386,11 +386,17 @@ class ApiKeyStore {
|
|
|
386
386
|
return status !== "active";
|
|
387
387
|
};
|
|
388
388
|
}
|
|
389
|
-
async revoke(kid, reason, atMs = Date.now()) {
|
|
389
|
+
async revoke(kid, reason, atMs = Date.now(), options = {}) {
|
|
390
|
+
const params = [kid, new Date(atMs).toISOString(), reason ?? null];
|
|
391
|
+
let scope = "";
|
|
392
|
+
if (options.app !== undefined) {
|
|
393
|
+
params.push(options.app);
|
|
394
|
+
scope = ` AND app = $${params.length}`;
|
|
395
|
+
}
|
|
390
396
|
const row = await this.client.get(`UPDATE ${this.table}
|
|
391
397
|
SET revoked_at = COALESCE(revoked_at, $2), revoked_reason = COALESCE(revoked_reason, $3)
|
|
392
|
-
WHERE kid = $1
|
|
393
|
-
RETURNING kid`,
|
|
398
|
+
WHERE kid = $1${scope}
|
|
399
|
+
RETURNING kid`, params);
|
|
394
400
|
return row !== null;
|
|
395
401
|
}
|
|
396
402
|
async touchLastUsed(kid, atMs = Date.now()) {
|
|
@@ -629,24 +635,43 @@ function serverDataBackendEnvKeys(name) {
|
|
|
629
635
|
databaseUrlKeys: [`HASNA_${token}_DATABASE_URL`, `${token}_DATABASE_URL`]
|
|
630
636
|
};
|
|
631
637
|
}
|
|
632
|
-
function
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
638
|
+
function definedDatabaseUrlEntries(env, keys) {
|
|
639
|
+
return keys.map((key) => ({ key, value: ownString(env, key) })).filter((entry) => entry.value !== undefined);
|
|
640
|
+
}
|
|
641
|
+
function assertPostgresqlDatabaseUrl(name, entries) {
|
|
642
|
+
const canonicalKey = serverDataBackendEnvKeys(name).databaseUrlKeys[0];
|
|
643
|
+
if (entries.length === 0) {
|
|
644
|
+
throw new Error(`${canonicalKey} is required; servers use PostgreSQL and never default to SQLite.`);
|
|
637
645
|
}
|
|
638
|
-
|
|
646
|
+
const blank = entries.filter((entry) => entry.value.trim().length === 0);
|
|
647
|
+
if (blank.length > 0) {
|
|
648
|
+
throw new Error(`${blank.map((entry) => entry.key).join(" and ")} is set but blank; a PostgreSQL database URL is required.`);
|
|
649
|
+
}
|
|
650
|
+
const controlled = entries.find((entry) => /[\u0000-\u001f\u007f]/.test(entry.value));
|
|
651
|
+
if (controlled)
|
|
652
|
+
throw new Error(`${controlled.key} must not contain ASCII control characters.`);
|
|
653
|
+
const normalized = entries.map((entry) => ({ key: entry.key, value: entry.value.trim() }));
|
|
654
|
+
if (normalized.length > 1 && new Set(normalized.map((entry) => entry.value)).size > 1) {
|
|
655
|
+
throw new Error(`${normalized.map((entry) => entry.key).join(" and ")} disagree; database URL aliases must be identical or only one may be set.`);
|
|
656
|
+
}
|
|
657
|
+
const selected = normalized[0];
|
|
658
|
+
let parsed;
|
|
659
|
+
try {
|
|
660
|
+
parsed = new URL(selected.value);
|
|
661
|
+
} catch {
|
|
662
|
+
throw new Error(`${selected.key} must be an absolute PostgreSQL connection URL.`);
|
|
663
|
+
}
|
|
664
|
+
if (parsed.protocol !== "postgres:" && parsed.protocol !== "postgresql:") {
|
|
665
|
+
throw new Error(`${selected.key} must use the postgres or postgresql scheme.`);
|
|
666
|
+
}
|
|
667
|
+
if (!parsed.hostname || parsed.pathname.length <= 1) {
|
|
668
|
+
throw new Error(`${selected.key} must name a PostgreSQL host and database.`);
|
|
669
|
+
}
|
|
670
|
+
return selected;
|
|
639
671
|
}
|
|
640
672
|
function resolveServerDataBackend(name, env = process.env) {
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
return {
|
|
644
|
-
backend: "sqlite",
|
|
645
|
-
source: "default",
|
|
646
|
-
databaseUrlPresent: false,
|
|
647
|
-
databaseUrlSource: null
|
|
648
|
-
};
|
|
649
|
-
}
|
|
673
|
+
const keys = serverDataBackendEnvKeys(name).databaseUrlKeys;
|
|
674
|
+
const databaseUrl = assertPostgresqlDatabaseUrl(name, definedDatabaseUrlEntries(env, keys));
|
|
650
675
|
return {
|
|
651
676
|
backend: "postgresql",
|
|
652
677
|
source: databaseUrl.key,
|
|
@@ -655,8 +680,8 @@ function resolveServerDataBackend(name, env = process.env) {
|
|
|
655
680
|
};
|
|
656
681
|
}
|
|
657
682
|
function resolveDatabaseUrl(name, env = process.env) {
|
|
658
|
-
const
|
|
659
|
-
return
|
|
683
|
+
const keys = serverDataBackendEnvKeys(name).databaseUrlKeys;
|
|
684
|
+
return assertPostgresqlDatabaseUrl(name, definedDatabaseUrlEntries(env, keys)).value;
|
|
660
685
|
}
|
|
661
686
|
// src/generated/storage-kit/tls.ts
|
|
662
687
|
import { readFileSync } from "fs";
|
|
@@ -903,9 +928,6 @@ function createServerPoolFromEnv(appName, options = {}) {
|
|
|
903
928
|
const env = own.env ?? process.env;
|
|
904
929
|
const resolution = resolveServerDataBackend(appName, env);
|
|
905
930
|
const connectionString = resolveDatabaseUrl(appName, env);
|
|
906
|
-
if (!connectionString) {
|
|
907
|
-
throw new Error(`postgresql storage for ${appName} needs a database URL. Set ` + `HASNA_${appName.toUpperCase().replace(/-/g, "_")}_DATABASE_URL.`);
|
|
908
|
-
}
|
|
909
931
|
const pool = createPgPool({
|
|
910
932
|
...own,
|
|
911
933
|
connectionString,
|
|
@@ -913,7 +935,7 @@ function createServerPoolFromEnv(appName, options = {}) {
|
|
|
913
935
|
});
|
|
914
936
|
return {
|
|
915
937
|
client: createQueryClient(pool),
|
|
916
|
-
connectionSource: resolution.databaseUrlSource
|
|
938
|
+
connectionSource: resolution.databaseUrlSource
|
|
917
939
|
};
|
|
918
940
|
}
|
|
919
941
|
// src/generated/storage-kit/migrations.ts
|
|
@@ -2680,11 +2702,44 @@ function parseArg(name, fallback) {
|
|
|
2680
2702
|
return process.argv[idx + 1];
|
|
2681
2703
|
return fallback;
|
|
2682
2704
|
}
|
|
2705
|
+
var USAGE = `domains-serve \u2014 standalone HTTP API server for @hasna/domains (PostgreSQL backend)
|
|
2706
|
+
|
|
2707
|
+
Usage: domains-serve [--port <n>] [--host <addr>]
|
|
2708
|
+
|
|
2709
|
+
Options:
|
|
2710
|
+
--port <n> Port to listen on (default: $PORT or ${DEFAULT_PORT})
|
|
2711
|
+
--host <addr> Address to bind (default: $HOST or 0.0.0.0)
|
|
2712
|
+
-h, --help Print this help and exit
|
|
2713
|
+
-V, --version Print the package version and exit
|
|
2714
|
+
|
|
2715
|
+
Environment:
|
|
2716
|
+
HASNA_DOMAINS_DATABASE_URL PostgreSQL DSN (falls back to DATABASE_URL)
|
|
2717
|
+
HASNA_DOMAINS_API_SIGNING_KEY HMAC signing secret for API keys
|
|
2718
|
+
(falls back to API_KEY_SIGNING_SECRET)`;
|
|
2719
|
+
function earlyArgAnswer(argv) {
|
|
2720
|
+
if (argv.includes("--help") || argv.includes("-h"))
|
|
2721
|
+
return USAGE;
|
|
2722
|
+
if (argv.includes("--version") || argv.includes("-V"))
|
|
2723
|
+
return getPackageVersion();
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2683
2726
|
async function main() {
|
|
2684
|
-
|
|
2685
|
-
|
|
2727
|
+
const early = earlyArgAnswer(process.argv);
|
|
2728
|
+
if (early !== undefined) {
|
|
2729
|
+
console.log(early);
|
|
2686
2730
|
return;
|
|
2687
2731
|
}
|
|
2732
|
+
await startDomainsServer({
|
|
2733
|
+
port: Number(parseArg("--port", process.env["PORT"]) ?? DEFAULT_PORT),
|
|
2734
|
+
host: parseArg("--host", process.env["HOST"]) ?? "0.0.0.0"
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
async function startDomainsServer(options) {
|
|
2738
|
+
const { port, host } = options;
|
|
2739
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
2740
|
+
throw new Error("Port must be an integer from 1 to 65535.");
|
|
2741
|
+
if (!host.trim())
|
|
2742
|
+
throw new Error("Host must not be blank.");
|
|
2688
2743
|
normalizeEnv();
|
|
2689
2744
|
const version = getPackageVersion();
|
|
2690
2745
|
const signingSecret = resolveSigningSecret();
|
|
@@ -2704,8 +2759,6 @@ async function main() {
|
|
|
2704
2759
|
}
|
|
2705
2760
|
}
|
|
2706
2761
|
});
|
|
2707
|
-
const port = Number(parseArg("--port", process.env["PORT"]) ?? DEFAULT_PORT) || DEFAULT_PORT;
|
|
2708
|
-
const host = parseArg("--host", process.env["HOST"]) ?? "0.0.0.0";
|
|
2709
2762
|
Bun.serve({
|
|
2710
2763
|
port,
|
|
2711
2764
|
hostname: host,
|
|
@@ -2728,7 +2781,9 @@ if (import.meta.main) {
|
|
|
2728
2781
|
});
|
|
2729
2782
|
}
|
|
2730
2783
|
export {
|
|
2784
|
+
startDomainsServer,
|
|
2731
2785
|
resolveSigningSecret,
|
|
2732
2786
|
normalizeEnv,
|
|
2787
|
+
USAGE,
|
|
2733
2788
|
SIGNING_KEY_ENVS
|
|
2734
2789
|
};
|
|
@@ -12,6 +12,41 @@ import { type Migration, type MigrationResult } from "../generated/storage-kit/i
|
|
|
12
12
|
/** Env var holding the owner-role DSN (DDL privileges). Falls back to the app DSN. */
|
|
13
13
|
export declare const OWNER_DSN_ENV = "HASNA_DOMAINS_DATABASE_URL_OWNER";
|
|
14
14
|
export declare const APP_DSN_ENV = "HASNA_DOMAINS_DATABASE_URL";
|
|
15
|
+
/**
|
|
16
|
+
* Applied-ledger rows recorded before the ledger's id scheme stabilized, which
|
|
17
|
+
* no build in this repo's history generates (verified across every published
|
|
18
|
+
* tarball 0.0.30-0.0.46 and all git history). They are acknowledged via the
|
|
19
|
+
* storage kit's `acknowledgedLegacyIds`: they pass the downgrade guard, are
|
|
20
|
+
* never checksum-compared (their SQL is not reproducible from any source), and
|
|
21
|
+
* are never re-applied or re-inserted.
|
|
22
|
+
*
|
|
23
|
+
* `domains_apikeys_tenancy_0001`, `domains_apikeys_tenancy_0002`,
|
|
24
|
+
* `domains_tenancy_0001`..`domains_tenancy_0010` were recorded against the
|
|
25
|
+
* prod ledger out-of-band during the 2026-07 self-hosted cutover. Deploy
|
|
26
|
+
* evidence 2026-08-25: the 02:00Z pass failed on `_0001` (O15-00671 filed);
|
|
27
|
+
* the 16:44Z pass, carrying the kit with `_0001` acknowledged
|
|
28
|
+
* (hasna/apps#1176), advanced to `_0002`; the next pass then failed on the
|
|
29
|
+
* third row `domains_tenancy_0001` (O15-00758 filed), the 2026-08-25 PASS-18
|
|
30
|
+
* pass then failed on the fourth row `domains_tenancy_0002` at
|
|
31
|
+
* `domains-prod-migrate:42` (O15-00762 filed), and the 2026-08-25 pass then
|
|
32
|
+
* failed on the fifth row `domains_tenancy_0003` at `domains-prod-migrate:42`
|
|
33
|
+
* (O15-00766 filed). Deploy evidence 2026-08-26: passes 48-96 then failed on
|
|
34
|
+
* the sixth row `domains_tenancy_0004` at `domains-prod-migrate:44` through
|
|
35
|
+
* `:49` (todos 2b474505). Deploy evidence 2026-08-26/27: the 2026-08-27
|
|
36
|
+
* 06:47Z pass failed on the seventh row `domains_tenancy_0005` at
|
|
37
|
+
* `domains-prod-migrate:50` (O15-01822 filed). The ledger census (inspection
|
|
38
|
+
* task oss-fleet-prod/4b7c37626965439e96d5386c8e8a73d4) shows the complete
|
|
39
|
+
* out-of-band set is the 12 rows below — `domains_apikeys_tenancy_0001-0002`
|
|
40
|
+
* plus `domains_tenancy_0001..0010` — so this list covers the full measured
|
|
41
|
+
* prod ledger rather than one row per deploy pass. The apikeys rows'
|
|
42
|
+
* substance — the api-keys tenancy (`tid`) column — is carried today by
|
|
43
|
+
* `hasna_auth_0003_api_keys_tenant`; the substance of the `domains_tenancy_*`
|
|
44
|
+
* rows is not reproducible from any source in this repo, and no build
|
|
45
|
+
* generates the ids, so they are acknowledged as history rather than
|
|
46
|
+
* re-applied. Acknowledging all twelve unblocks `domains db migrate` (the ECS
|
|
47
|
+
* migrate task) and therefore the domains deploy lane.
|
|
48
|
+
*/
|
|
49
|
+
export declare const ACKNOWLEDGED_LEGACY_MIGRATION_IDS: readonly string[];
|
|
15
50
|
/** The ordered migration set: app schema first, then the shared api-keys table. */
|
|
16
51
|
export declare function buildMigrations(): Migration[];
|
|
17
52
|
/** Run all pending migrations against the owner DSN. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/server/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAC;AAK3C,sFAAsF;AACtF,eAAO,MAAM,aAAa,qCAAqC,CAAC;AAChE,eAAO,MAAM,WAAW,+BAA+B,CAAC;AAGxD,mFAAmF;AACnF,wBAAgB,eAAe,IAAI,SAAS,EAAE,CAU7C;AAYD,wDAAwD;AACxD,wBAAsB,aAAa,CACjC,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,GACvD,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/server/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAC;AAK3C,sFAAsF;AACtF,eAAO,MAAM,aAAa,qCAAqC,CAAC;AAChE,eAAO,MAAM,WAAW,+BAA+B,CAAC;AAGxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,iCAAiC,EAAE,SAAS,MAAM,EAa9D,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,eAAe,IAAI,SAAS,EAAE,CAU7C;AAYD,wDAAwD;AACxD,wBAAsB,aAAa,CACjC,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,GACvD,OAAO,CAAC,eAAe,CAAC,CAa1B"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/domains",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Domain portfolio, registrar, marketplace, and DNS management for AI agents — CLI + MCP + HTTP API + SDK,
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Domain portfolio, registrar, marketplace, and DNS management for AI agents — CLI + MCP + HTTP API + SDK, shared account API and PostgreSQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
"files": [
|
|
48
48
|
"dist",
|
|
49
49
|
"LICENSE",
|
|
50
|
-
"README.md"
|
|
50
|
+
"README.md",
|
|
51
|
+
"postinstall.js"
|
|
51
52
|
],
|
|
52
53
|
"scripts": {
|
|
53
54
|
"clean": "rm -rf dist",
|
|
@@ -60,9 +61,9 @@
|
|
|
60
61
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
61
62
|
"dev:serve": "bun run src/server/index.ts",
|
|
62
63
|
"prepublishOnly": "bun run build",
|
|
63
|
-
"postinstall": "
|
|
64
|
+
"postinstall": "node postinstall.js",
|
|
64
65
|
"prepack": "bun run build && bun run artifact-scan",
|
|
65
|
-
"artifact-scan": "bun pm pack --ignore-scripts --quiet --filename \"$PWD/domains-artifact-scan.tgz\" && bunx @hasna/contracts@0.
|
|
66
|
+
"artifact-scan": "bun pm pack --ignore-scripts --quiet --filename \"$PWD/domains-artifact-scan.tgz\" && bunx @hasna/contracts@1.0.2 artifact-scan domains-artifact-scan.tgz; rc=$?; rm -f \"$PWD/domains-artifact-scan.tgz\"; exit $rc"
|
|
66
67
|
},
|
|
67
68
|
"keywords": [
|
|
68
69
|
"domains",
|
|
@@ -97,7 +98,6 @@
|
|
|
97
98
|
"@aws-sdk/client-route-53": "^3.1067.0",
|
|
98
99
|
"@aws-sdk/client-route-53-domains": "^3.1067.0",
|
|
99
100
|
"@aws-sdk/credential-provider-ini": "3.972.53",
|
|
100
|
-
"@hasna/contracts": "0.14.1",
|
|
101
101
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
102
102
|
"chalk": "^5.4.1",
|
|
103
103
|
"commander": "^13.1.0",
|
|
@@ -119,8 +119,8 @@
|
|
|
119
119
|
}
|
|
120
120
|
},
|
|
121
121
|
"devDependencies": {
|
|
122
|
-
"@hasna/
|
|
123
|
-
"@types/bun": "
|
|
122
|
+
"@hasna/contracts": "1.0.2",
|
|
123
|
+
"@types/bun": "1.3.14",
|
|
124
124
|
"@types/pg": "^8.20.0",
|
|
125
125
|
"@types/react": "^18.3.18",
|
|
126
126
|
"bun-types": "1.3.14",
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Best-effort install-time creation of the domains LOCAL DATA home directory,
|
|
2
|
+
// resolving the SAME effective home the runtime uses (src/lib/app-home.ts):
|
|
3
|
+
// an exact-app override (HASNA_DOMAINS_HOME / HASNA_DOMAINS_DIR, then the
|
|
4
|
+
// legacy unprefixed DOMAINS_HOME / DOMAINS_DIR aliases) wins; otherwise
|
|
5
|
+
// $HASNA_HOME/domains (the shared root override); otherwise the legacy
|
|
6
|
+
// ~/.hasna/domains default. Faithfully mirrors the runtime module — no
|
|
7
|
+
// @hasna/paths, no XDG, no HASNA_*_HOME kind overrides (stripped, hasna/apps#1720
|
|
8
|
+
// class B). Failures are non-fatal: the runtime creates the same directory on
|
|
9
|
+
// first use.
|
|
10
|
+
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const env = process.env;
|
|
16
|
+
const override = (
|
|
17
|
+
env["HASNA_DOMAINS_HOME"] ||
|
|
18
|
+
env["HASNA_DOMAINS_DIR"] ||
|
|
19
|
+
env["DOMAINS_HOME"] ||
|
|
20
|
+
env["DOMAINS_DIR"] ||
|
|
21
|
+
""
|
|
22
|
+
).trim();
|
|
23
|
+
const home = env["HOME"] || env["USERPROFILE"] || homedir();
|
|
24
|
+
|
|
25
|
+
let dir;
|
|
26
|
+
if (override) {
|
|
27
|
+
dir = override;
|
|
28
|
+
} else {
|
|
29
|
+
const hasnaHome = (env["HASNA_HOME"] || "").trim();
|
|
30
|
+
dir = hasnaHome ? join(hasnaHome, "domains") : join(home, ".hasna", "domains");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
34
|
+
try {
|
|
35
|
+
chmodSync(dir, 0o700);
|
|
36
|
+
} catch {
|
|
37
|
+
// best-effort on platforms without POSIX perms
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
// never fail an install over pre-created directories
|
|
41
|
+
}
|