@neta-art/cohub-cli 10.11.1 → 10.12.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 +9 -0
- package/dist/commands/app-domains.d.ts +2 -0
- package/dist/commands/app-domains.js +133 -0
- package/dist/commands/apps.js +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -496,6 +496,15 @@ cohub apps versions <appId> --json
|
|
|
496
496
|
cohub apps rm <appId> --yes
|
|
497
497
|
```
|
|
498
498
|
|
|
499
|
+
Bind a custom domain to a published public App. The binding costs a one-time $5, charged when the domain goes live; `add` prints the CNAME and TXT records to create at the DNS provider:
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
cohub apps domains add <app> app.example.com --yes
|
|
503
|
+
cohub apps domains ls <app>
|
|
504
|
+
cohub apps domains check <app> app.example.com
|
|
505
|
+
cohub apps domains rm <app> app.example.com --yes
|
|
506
|
+
```
|
|
507
|
+
|
|
499
508
|
Resolve a published App by public identity:
|
|
500
509
|
|
|
501
510
|
```bash
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { normalizeAppDomainHostname } from "@neta-art/cohub";
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
import { getAppByRef } from "../app-ref.js";
|
|
4
|
+
import { error, handleHttp, json as outJson, jsonRequested, ok, table } from "../output.js";
|
|
5
|
+
async function confirm(question, opts, hint) {
|
|
6
|
+
if (opts.yes)
|
|
7
|
+
return;
|
|
8
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
9
|
+
return error("Confirmation required", hint);
|
|
10
|
+
process.stdout.write(`${question} [y/N] `);
|
|
11
|
+
const chunks = [];
|
|
12
|
+
for await (const chunk of process.stdin) {
|
|
13
|
+
chunks.push(chunk);
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
const answer = Buffer.concat(chunks).toString().trim().toLowerCase();
|
|
17
|
+
if (answer !== "y" && answer !== "yes")
|
|
18
|
+
return error("Cancelled");
|
|
19
|
+
}
|
|
20
|
+
async function findDomain(client, appId, ref) {
|
|
21
|
+
const { domains } = await client.apps.listDomains(appId);
|
|
22
|
+
const target = normalizeAppDomainHostname(ref) ?? ref.trim().toLowerCase();
|
|
23
|
+
const domain = domains.find((item) => item.id === ref || item.hostname === target);
|
|
24
|
+
return domain ?? error(`Domain not found: ${ref}`, "Run `cohub apps domains ls <app>` to see the App's domains.");
|
|
25
|
+
}
|
|
26
|
+
const info = (message) => console.log(message);
|
|
27
|
+
function printDomain(domain) {
|
|
28
|
+
table([{
|
|
29
|
+
hostname: domain.hostname,
|
|
30
|
+
status: domain.status,
|
|
31
|
+
certificate: domain.certificateStatus ?? "-",
|
|
32
|
+
error: domain.error?.message ?? "",
|
|
33
|
+
}], [
|
|
34
|
+
{ key: "hostname", label: "Hostname" },
|
|
35
|
+
{ key: "status", label: "Status" },
|
|
36
|
+
{ key: "certificate", label: "Certificate" },
|
|
37
|
+
{ key: "error", label: "Error" },
|
|
38
|
+
]);
|
|
39
|
+
if (domain.status === "active")
|
|
40
|
+
return;
|
|
41
|
+
info("Add these DNS records at your DNS provider:");
|
|
42
|
+
table(domain.dnsRecords.map((record) => ({
|
|
43
|
+
...record,
|
|
44
|
+
state: record.satisfied === true ? "ok" : record.satisfied === false ? "missing" : "-",
|
|
45
|
+
})), [
|
|
46
|
+
{ key: "type", label: "Type" },
|
|
47
|
+
{ key: "name", label: "Name" },
|
|
48
|
+
{ key: "value", label: "Value" },
|
|
49
|
+
{ key: "state", label: "State" },
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
export function registerAppDomains(appsCmd) {
|
|
53
|
+
const domainsCmd = appsCmd.command("domains").description("Custom domains for published Apps");
|
|
54
|
+
domainsCmd
|
|
55
|
+
.command("list <app>")
|
|
56
|
+
.alias("ls")
|
|
57
|
+
.description("List the App's custom domains")
|
|
58
|
+
.option("--json", "Output as JSON")
|
|
59
|
+
.action(async (appRef, opts) => {
|
|
60
|
+
const client = createClient();
|
|
61
|
+
try {
|
|
62
|
+
const detail = await getAppByRef(client, appRef);
|
|
63
|
+
const result = await client.apps.listDomains(detail.app.id);
|
|
64
|
+
if (jsonRequested(opts))
|
|
65
|
+
return outJson(result);
|
|
66
|
+
if (!result.enabled && result.domains.length === 0)
|
|
67
|
+
return info("Custom domains are not enabled on this deployment.");
|
|
68
|
+
if (result.domains.length === 0)
|
|
69
|
+
return info(`No custom domain. Add one with \`cohub apps domains add ${appRef} <hostname>\` ($${result.priceUsd}, one-time).`);
|
|
70
|
+
result.domains.forEach(printDomain);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
handleHttp(e);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
domainsCmd
|
|
77
|
+
.command("add <app> <hostname>")
|
|
78
|
+
.description("Bind a custom domain; charged once when it goes live")
|
|
79
|
+
.option("-y, --yes", "Confirm the one-time charge")
|
|
80
|
+
.option("--json", "Output as JSON")
|
|
81
|
+
.action(async (appRef, hostname, opts) => {
|
|
82
|
+
const client = createClient();
|
|
83
|
+
try {
|
|
84
|
+
const detail = await getAppByRef(client, appRef);
|
|
85
|
+
const { priceUsd } = await client.apps.listDomains(detail.app.id);
|
|
86
|
+
await confirm(`Binding ${hostname} costs $${priceUsd}, charged once when the domain goes live. Continue?`, opts, `Pass --yes to accept the one-time $${priceUsd} charge.`);
|
|
87
|
+
const { domain } = await client.apps.addDomain(detail.app.id, hostname);
|
|
88
|
+
if (jsonRequested(opts))
|
|
89
|
+
return outJson(domain);
|
|
90
|
+
ok(`Domain added: ${domain.hostname}`);
|
|
91
|
+
printDomain(domain);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
handleHttp(e);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
domainsCmd
|
|
98
|
+
.command("check <app> <domain>")
|
|
99
|
+
.description("Check DNS and certificate status now")
|
|
100
|
+
.option("--json", "Output as JSON")
|
|
101
|
+
.action(async (appRef, domainRef, opts) => {
|
|
102
|
+
const client = createClient();
|
|
103
|
+
try {
|
|
104
|
+
const detail = await getAppByRef(client, appRef);
|
|
105
|
+
const target = await findDomain(client, detail.app.id, domainRef);
|
|
106
|
+
const { domain } = await client.apps.checkDomain(detail.app.id, target.id);
|
|
107
|
+
if (jsonRequested(opts))
|
|
108
|
+
return outJson(domain);
|
|
109
|
+
printDomain(domain);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
handleHttp(e);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
domainsCmd
|
|
116
|
+
.command("rm <app> <domain>")
|
|
117
|
+
.alias("remove")
|
|
118
|
+
.description("Remove a custom domain")
|
|
119
|
+
.option("-y, --yes", "Confirm removal")
|
|
120
|
+
.action(async (appRef, domainRef, opts) => {
|
|
121
|
+
const client = createClient();
|
|
122
|
+
try {
|
|
123
|
+
const detail = await getAppByRef(client, appRef);
|
|
124
|
+
const target = await findDomain(client, detail.app.id, domainRef);
|
|
125
|
+
await confirm(`Remove ${target.hostname}? The one-time charge is not refunded.`, opts, "Pass --yes to remove the domain.");
|
|
126
|
+
const result = await client.apps.removeDomain(detail.app.id, target.id);
|
|
127
|
+
ok(result.domain ? `Removing ${target.hostname}; its certificate is being released` : `Domain removed: ${target.hostname}`);
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
handleHttp(e);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
package/dist/commands/apps.js
CHANGED
|
@@ -9,6 +9,7 @@ import { getAppByRef, parseAppRef } from "../app-ref.js";
|
|
|
9
9
|
import { checkAppTarget } from "../app-target.js";
|
|
10
10
|
import { putBytes, putLocalFile } from "../http-put.js";
|
|
11
11
|
import { registerAppCommerce } from "./app-commerce.js";
|
|
12
|
+
import { registerAppDomains } from "./app-domains.js";
|
|
12
13
|
import { collectPublicUpload } from "./public.js";
|
|
13
14
|
const APP_STATUSES = ["published", "disabled"];
|
|
14
15
|
const APP_VISIBILITIES = ["public", "space"];
|
|
@@ -722,6 +723,7 @@ export function registerApps(program) {
|
|
|
722
723
|
}
|
|
723
724
|
});
|
|
724
725
|
registerAppCommerce(appsCmd);
|
|
726
|
+
registerAppDomains(appsCmd);
|
|
725
727
|
// ── Viewer grants ─────────────────────────────────────────────────────────
|
|
726
728
|
appsCmd
|
|
727
729
|
.command("authorize <app>")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.12.0",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"NOTICE"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@neta-art/cohub": "12.
|
|
21
|
+
"@neta-art/cohub": "12.5.0",
|
|
22
22
|
"@neta-art/generation": "^0.1.40",
|
|
23
23
|
"commander": "^15.0.0",
|
|
24
24
|
"sharp": "^0.35.4",
|