@faable/faable 4.12.0 → 4.13.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.
|
@@ -2,7 +2,7 @@ import { requireApi } from '../../../api/context.js';
|
|
|
2
2
|
import { print_json, json_option } from '../../../lib/listing.js';
|
|
3
3
|
import { log } from '../../../log.js';
|
|
4
4
|
import { resolve_app_id } from '../resolve_app_id.js';
|
|
5
|
-
import { cname_target } from './format.js';
|
|
5
|
+
import { acme_record, cname_target } from './format.js';
|
|
6
6
|
|
|
7
7
|
const domains_add = {
|
|
8
8
|
command: 'add <fqdn>',
|
|
@@ -37,7 +37,11 @@ const domains_add = {
|
|
|
37
37
|
// Same shape as `domains check --json`: the record plus the CNAME to
|
|
38
38
|
// create, which is the whole next step.
|
|
39
39
|
if (args.json) {
|
|
40
|
-
return print_json({
|
|
40
|
+
return print_json({
|
|
41
|
+
...domain,
|
|
42
|
+
expected_cname: cname_target(domain),
|
|
43
|
+
...(args.tls ? { prevalidation_cname: acme_record(domain) } : {})
|
|
44
|
+
});
|
|
41
45
|
}
|
|
42
46
|
log.info(`🌐 Domain ${domain.fqdn} added to ${app.name} (${app_id}).`);
|
|
43
47
|
log.info(``);
|
|
@@ -45,6 +49,13 @@ const domains_add = {
|
|
|
45
49
|
log.info(` ${domain.fqdn} → ${cname_target(domain)}`);
|
|
46
50
|
log.info(``);
|
|
47
51
|
log.info(`Faable verifies the record automatically once DNS propagates${args.tls ? ' and then provisions the TLS certificate' : ''}.`);
|
|
52
|
+
if (args.tls) {
|
|
53
|
+
const acme = acme_record(domain);
|
|
54
|
+
log.info(``);
|
|
55
|
+
log.info(`Already serving ${domain.fqdn} somewhere else? Create this record FIRST and leave the CNAME above for later:`);
|
|
56
|
+
log.info(` ${acme.name} → ${acme.target}`);
|
|
57
|
+
log.info(`Faable then issues the certificate before any traffic moves, and switching the CNAME has no TLS gap.`);
|
|
58
|
+
}
|
|
48
59
|
log.info(`Track it with: faable deploy domains check ${domain.fqdn}`);
|
|
49
60
|
}
|
|
50
61
|
};
|
|
@@ -2,7 +2,7 @@ import { requireApi } from '../../../api/context.js';
|
|
|
2
2
|
import { print_json, json_option } from '../../../lib/listing.js';
|
|
3
3
|
import { log } from '../../../log.js';
|
|
4
4
|
import { resolve_app_id } from '../resolve_app_id.js';
|
|
5
|
-
import { find_by_fqdn, cname_target, dns_badge } from './format.js';
|
|
5
|
+
import { find_by_fqdn, acme_record, cname_target, dns_badge } from './format.js';
|
|
6
6
|
|
|
7
7
|
const domains_check = {
|
|
8
8
|
command: 'check <fqdn>',
|
|
@@ -30,7 +30,11 @@ const domains_check = {
|
|
|
30
30
|
}
|
|
31
31
|
// The record plus the one thing it does not carry: the CNAME to create.
|
|
32
32
|
if (args.json) {
|
|
33
|
-
return print_json({
|
|
33
|
+
return print_json({
|
|
34
|
+
...domain,
|
|
35
|
+
expected_cname: cname_target(domain),
|
|
36
|
+
...(domain.tls ? { prevalidation_cname: acme_record(domain) } : {})
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
const status = domain.status;
|
|
36
40
|
log.info(`🌐 ${domain.fqdn} — ${dns_badge(domain)}`);
|
|
@@ -44,6 +48,12 @@ const domains_check = {
|
|
|
44
48
|
if (status?.dns_message) {
|
|
45
49
|
log.info(` Diagnostic: ${status.dns_message}`);
|
|
46
50
|
}
|
|
51
|
+
if (domain.tls) {
|
|
52
|
+
const acme = acme_record(domain);
|
|
53
|
+
log.info(` Pre-validation: ${acme.name} → ${acme.target} ${acme.ready
|
|
54
|
+
? '✅ in place: the certificate is issued without waiting for the CNAME'
|
|
55
|
+
: '(optional; for a domain live elsewhere, so the move has no TLS gap)'}`);
|
|
56
|
+
}
|
|
47
57
|
if (status?.dns_checked_at) {
|
|
48
58
|
log.info(` Last checked: ${status.dns_checked_at}`);
|
|
49
59
|
}
|
|
@@ -19,6 +19,15 @@ const dns_badge = (domain) => {
|
|
|
19
19
|
// value); fall back to deriving it from the id so `add` can print
|
|
20
20
|
// instructions even before the first DNS check populates the status.
|
|
21
21
|
const cname_target = (domain) => domain.status?.dns_expected?.[0] ?? `${domain.id}.faable.link`;
|
|
22
|
+
// The optional record that gets the certificate issued BEFORE the domain
|
|
23
|
+
// points here: a domain that is live somewhere else moves without a TLS gap.
|
|
24
|
+
// Published by the api in `status.acme_expected`; derived from the id until
|
|
25
|
+
// the first check fills it in, like the CNAME above.
|
|
26
|
+
const acme_record = (domain) => ({
|
|
27
|
+
name: `_acme-challenge.${domain.fqdn}`,
|
|
28
|
+
target: domain.status?.acme_expected?.[0] ?? `${domain.id}.acme.faable.com`,
|
|
29
|
+
ready: domain.status?.acme_state === 'ok'
|
|
30
|
+
});
|
|
22
31
|
const find_by_fqdn = (domains, fqdn) => domains.find(d => d.fqdn.toLowerCase() === fqdn.toLowerCase());
|
|
23
32
|
|
|
24
|
-
export { cname_target, dns_badge, find_by_fqdn };
|
|
33
|
+
export { acme_record, cname_target, dns_badge, find_by_fqdn };
|
package/dist/mcp/tools.js
CHANGED
|
@@ -352,7 +352,7 @@ const TOOLS = [
|
|
|
352
352
|
{
|
|
353
353
|
name: 'check_domain',
|
|
354
354
|
title: 'Check a domain',
|
|
355
|
-
description: 'DNS diagnostic of one custom domain: the CNAME it expects, what DNS answers today, and why it is not verified yet.',
|
|
355
|
+
description: 'DNS diagnostic of one custom domain: the CNAME it expects, what DNS answers today, and why it is not verified yet. `prevalidation_cname.ready` says whether the optional `_acme-challenge` record is in place, so the certificate is issued without waiting for the CNAME.',
|
|
356
356
|
input: {
|
|
357
357
|
app,
|
|
358
358
|
project,
|
|
@@ -782,7 +782,7 @@ const TOOLS = [
|
|
|
782
782
|
{
|
|
783
783
|
name: 'add_domain',
|
|
784
784
|
title: 'Add a custom domain',
|
|
785
|
-
description:
|
|
785
|
+
description: "Attach a custom domain to an app. Returns the CNAME record the user must create at their DNS provider; Faable verifies it and issues the certificate on its own. If the domain already serves traffic somewhere else, tell the user to create `prevalidation_cname` (`_acme-challenge.<fqdn>` CNAME) FIRST and switch the main CNAME only once check_domain shows it ready: the certificate then exists before traffic moves, with no TLS gap.",
|
|
786
786
|
input: { app, project, fqdn: z.string().describe('e.g. www.example.com') },
|
|
787
787
|
command: ['deploy', 'domains', 'add'],
|
|
788
788
|
flags: a => [a.fqdn, ...target(a)],
|