ninepm 0.72.0 → 0.78.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 +30 -7
- package/dist/dns-host.d.ts +8 -0
- package/dist/dns-host.js +16 -0
- package/dist/dns-providers.d.ts +91 -0
- package/dist/dns-providers.js +194 -0
- package/dist/domain-state.d.ts +147 -0
- package/dist/domain-state.js +248 -0
- package/dist/index.d.ts +48 -46
- package/dist/index.js +337 -118
- package/package.json +1 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-cli-package.mjs from the in-repo CLI source -- do not edit.
|
|
2
|
+
// Edit src/cli or src/shared instead; this is regenerated on typecheck/test/build/pack.
|
|
3
|
+
// One plain-language status for a custom domain (#1994): which of six states it is in, why,
|
|
4
|
+
// and the one thing that happens next. The control plane computes it after its DNS check and
|
|
5
|
+
// sends it on every domain; the CLI and the dashboard derive it from this same file when they
|
|
6
|
+
// meet a server that predates the field, so the two paths cannot disagree. Copied into the CLI
|
|
7
|
+
// tarball by scripts/generate-cli-package.mjs, so it imports nothing but dns-host and
|
|
8
|
+
// dns-providers, which are copied beside it.
|
|
9
|
+
import { relativeRecordName, zoneApexFor } from "./dns-host.js";
|
|
10
|
+
import { dnsProviderProfile } from "./dns-providers.js";
|
|
11
|
+
// The markers the control plane writes into provisioningError. Matched as exact strings, so a
|
|
12
|
+
// wording change here changes what every reader recognises at once; the server's reconcilers
|
|
13
|
+
// import them from this file for the same reason.
|
|
14
|
+
// #751: the expired marker. Deliberately static - no configured day-count inside it - because
|
|
15
|
+
// the reconcilers, claim checks and quota carve-outs key on this exact string.
|
|
16
|
+
export const CUSTOM_DOMAIN_EXPIRED_MESSAGE = "This domain was removed because its DNS verification was never completed. Add the domain again to retry.";
|
|
17
|
+
/** The name the CLI has always exported the expired marker under. */
|
|
18
|
+
export const CUSTOM_DOMAIN_EXPIRED_TEXT = CUSTOM_DOMAIN_EXPIRED_MESSAGE;
|
|
19
|
+
// Written onto a domain row when its app is in private_service mode, the only mode whose
|
|
20
|
+
// domains are torn down (#750 kept them for otp/idp).
|
|
21
|
+
export const CUSTOM_DOMAINS_SERVICE_MODE_MESSAGE = "Custom domains are not available for service-token apps, so this domain's hostname was removed. Switching the app to another access mode sets it up again, with new DNS verification values to publish.";
|
|
22
|
+
// The wording rows torn down by earlier releases still carry. It says custom domains are
|
|
23
|
+
// public-only, which is false (otp/idp apps keep theirs), so it is recognised and replaced.
|
|
24
|
+
export const LEGACY_SERVICE_MODE_MESSAGE = "Custom domains are available only for public apps.";
|
|
25
|
+
/** Whether a stored error is the service-mode teardown marker, in either wording. */
|
|
26
|
+
export function isServiceModeProvisioningError(error) {
|
|
27
|
+
return error === CUSTOM_DOMAINS_SERVICE_MODE_MESSAGE || error === LEGACY_SERVICE_MODE_MESSAGE;
|
|
28
|
+
}
|
|
29
|
+
// Written when the platform has no fallback script, so nothing can create, re-adopt or tear
|
|
30
|
+
// down this domain's route.
|
|
31
|
+
export const CUSTOM_DOMAINS_NOT_CONFIGURED_MESSAGE = "Custom domains are not fully configured on this platform.";
|
|
32
|
+
// Written when another script's route already holds the hostname.
|
|
33
|
+
export const CUSTOM_DOMAIN_ROUTE_CONFLICT_MESSAGE = "This domain is already claimed elsewhere on the platform. Contact support to release it.";
|
|
34
|
+
function normalizeDnsName(value) {
|
|
35
|
+
return value.trim().toLowerCase().replace(/\.$/, "");
|
|
36
|
+
}
|
|
37
|
+
// The value the server's DNS check compares against: TXT verbatim, names lowercased without a root dot.
|
|
38
|
+
function checkedRecordValue(type, value) {
|
|
39
|
+
return type === "TXT" ? value : normalizeDnsName(value);
|
|
40
|
+
}
|
|
41
|
+
export function domainRecordStatuses(domain) {
|
|
42
|
+
const apex = zoneApexFor(domain.hostname, domain.dnsCheck?.zone);
|
|
43
|
+
return domain.dnsInstructions.map((instruction) => {
|
|
44
|
+
const type = instruction.type.toUpperCase();
|
|
45
|
+
const fqdn = normalizeDnsName(instruction.host);
|
|
46
|
+
const expected = checkedRecordValue(type, instruction.value);
|
|
47
|
+
// Matched on the expected value as well as host and type: the two TXT values of one name
|
|
48
|
+
// are separate rows, and keying on host and type alone gives both rows one verdict (#1986).
|
|
49
|
+
const seen = domain.dnsCheck?.records.find((entry) => entry.type.toUpperCase() === type && normalizeDnsName(entry.host) === fqdn && entry.expected === expected);
|
|
50
|
+
const atApex = type === "CNAME" && fqdn === apex;
|
|
51
|
+
const check = domainRecordCheck(seen, atApex);
|
|
52
|
+
return {
|
|
53
|
+
type,
|
|
54
|
+
name: relativeRecordName(fqdn, apex),
|
|
55
|
+
fqdn,
|
|
56
|
+
expected: instruction.value,
|
|
57
|
+
current: seen ? seen.current : null,
|
|
58
|
+
ok: check === "found" ? true : check === "missing" || check === "different" || check === "doubled" ? false : null,
|
|
59
|
+
check,
|
|
60
|
+
...(check === "doubled" && seen?.doubledAt ? { doubledAt: seen.doubledAt } : {}),
|
|
61
|
+
apex: atApex,
|
|
62
|
+
optional: instruction.optional === true,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const IP_ADDRESS = /^(\d{1,3}(\.\d{1,3}){3}|[0-9a-f:]*:[0-9a-f:.]+)$/i;
|
|
67
|
+
// The server looks a CNAME up and, finding none, falls back to the name's A records. At the
|
|
68
|
+
// zone root that is exactly what a correct ALIAS/ANAME or flattened CNAME answers: addresses,
|
|
69
|
+
// never the target name. So addresses at the apex are not evidence of a wrong record; they
|
|
70
|
+
// cannot be compared from outside at all.
|
|
71
|
+
function domainRecordCheck(seen, atApex) {
|
|
72
|
+
if (!seen)
|
|
73
|
+
return "not_checked";
|
|
74
|
+
if (seen.matches)
|
|
75
|
+
return "found";
|
|
76
|
+
if (seen.doubledAt)
|
|
77
|
+
return "doubled";
|
|
78
|
+
if (seen.current.length === 0)
|
|
79
|
+
return "missing";
|
|
80
|
+
if (atApex && seen.current.every((value) => IP_ADDRESS.test(value.trim())))
|
|
81
|
+
return "apex_addresses";
|
|
82
|
+
return "different";
|
|
83
|
+
}
|
|
84
|
+
// Unproven is decided by `ok`, not by listing check values: a check this code does not know yet
|
|
85
|
+
// carries ok null and so reads as unknown, never as found. The one exception is an apex
|
|
86
|
+
// answering with addresses, which the platform's own active routing vouches for.
|
|
87
|
+
function isUnproven(record, routingActive) {
|
|
88
|
+
if (record.ok !== null)
|
|
89
|
+
return false;
|
|
90
|
+
return !(record.check === "apex_addresses" && routingActive);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The `www.<domain>` to connect instead, when this hostname is a bare domain whose DNS host
|
|
94
|
+
* cannot point a root at a hostname at all (#1996): GoDaddy, Route 53, IONOS, Wix. Read only
|
|
95
|
+
* from a host the check both named and identified, so an unknown host, an older server and a
|
|
96
|
+
* domain with no check keep the ordinary records. Routing that is already active is the
|
|
97
|
+
* platform's own evidence that the root record exists, and wins over the profile.
|
|
98
|
+
*/
|
|
99
|
+
export function rootUnsupportedWwwHostname(domain) {
|
|
100
|
+
const check = domain.dnsCheck;
|
|
101
|
+
if (!check?.provider || domain.routingStatus === "active")
|
|
102
|
+
return null;
|
|
103
|
+
if (dnsProviderProfile(check.providerId)?.apex.support !== "none")
|
|
104
|
+
return null;
|
|
105
|
+
const host = domain.hostname.toLowerCase().replace(/\.$/, "");
|
|
106
|
+
return host === zoneApexFor(host, check.zone) ? `www.${host}` : null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Whether a domain's instructions show "connect www instead" in place of the root record. It
|
|
110
|
+
* reads the status's own next step, so the display and the status cannot disagree: routing
|
|
111
|
+
* that is already active, an unknown host or an older server never show it, and a server's
|
|
112
|
+
* verdict is honoured even for a host this copy's table does not know.
|
|
113
|
+
*/
|
|
114
|
+
export function showsUseWww(next) {
|
|
115
|
+
return next?.action === "use_www";
|
|
116
|
+
}
|
|
117
|
+
export function deriveDomainState(domain, records = domainRecordStatuses(domain)) {
|
|
118
|
+
if (domain.provisioningError === CUSTOM_DOMAIN_EXPIRED_MESSAGE)
|
|
119
|
+
return "expired";
|
|
120
|
+
if (domain.routingStatus === "failed" || domain.tlsStatus === "failed" || domain.provisioningError)
|
|
121
|
+
return "failed";
|
|
122
|
+
if (domain.routingStatus === "active" && domain.tlsStatus === "active")
|
|
123
|
+
return "live";
|
|
124
|
+
// No record the owner can publish will finish this domain: it waits on the owner choosing www.
|
|
125
|
+
if (rootUnsupportedWwwHostname(domain))
|
|
126
|
+
return "waiting_for_dns";
|
|
127
|
+
const required = records.filter((record) => !record.optional);
|
|
128
|
+
if (required.some((record) => record.ok === false))
|
|
129
|
+
return "waiting_for_dns";
|
|
130
|
+
const routingActive = domain.routingStatus === "active";
|
|
131
|
+
// An apex answering with addresses defers to the platform's own routing check: active means
|
|
132
|
+
// it found the record, pending means it has not yet.
|
|
133
|
+
const unproven = required.some((record) => isUnproven(record, routingActive));
|
|
134
|
+
if (unproven || (!domain.dnsCheck && required.length === 0)) {
|
|
135
|
+
// Routing still pending is the platform's own evidence that it has not seen the records.
|
|
136
|
+
return routingActive ? "dns_unverified" : "waiting_for_dns";
|
|
137
|
+
}
|
|
138
|
+
return "issuing_certificate";
|
|
139
|
+
}
|
|
140
|
+
function nextRecord(record) {
|
|
141
|
+
const action = record.ok === false ? (record.check === "different" && record.type !== "TXT" ? "replace" : "add") : "confirm";
|
|
142
|
+
return { type: record.type, host: record.fqdn, value: record.expected, action, check: record.check };
|
|
143
|
+
}
|
|
144
|
+
// Who controls the CAA record that decides, which decides the advice: in the owner's own zone
|
|
145
|
+
// they can add an entry; at a CNAME target only whoever runs that name can; and when the
|
|
146
|
+
// resolver did not say, nothing is handed over to edit at a name the owner may not control.
|
|
147
|
+
function caaNext(caa) {
|
|
148
|
+
const summary = {
|
|
149
|
+
recordName: caa.recordName,
|
|
150
|
+
...(caa.via ? { via: caa.via } : {}),
|
|
151
|
+
...(caa.ownerUnknown ? { ownerUnknown: true } : {}),
|
|
152
|
+
platformIssuers: caa.platformIssuers,
|
|
153
|
+
};
|
|
154
|
+
if (caa.via)
|
|
155
|
+
return { who: "owner", action: "ask_caa_controller", caa: summary };
|
|
156
|
+
if (caa.ownerUnknown)
|
|
157
|
+
return { who: "owner", action: "check_caa", caa: summary };
|
|
158
|
+
const issuer = caa.platformIssuers[0];
|
|
159
|
+
return {
|
|
160
|
+
who: "owner",
|
|
161
|
+
action: "allow_ca_in_your_zone",
|
|
162
|
+
caa: summary,
|
|
163
|
+
...(issuer ? { records: [{ type: "CAA", host: caa.recordName, value: `0 issue "${issuer}"`, action: "add", check: "missing" }] } : {}),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The state, why, and the one next step. `state` is exactly deriveDomainState's; `reason` and
|
|
168
|
+
* `next` only refine it. Two rules hold throughout: a record nobody looked at is never called
|
|
169
|
+
* missing (it gets confirm_records, never add), and nothing here restarts validation or
|
|
170
|
+
* suggests that a restart speeds things up - Start over is named only for a failed certificate.
|
|
171
|
+
*/
|
|
172
|
+
export function deriveDomainStatus(domain, options = {}) {
|
|
173
|
+
const records = domainRecordStatuses(domain);
|
|
174
|
+
const state = deriveDomainState(domain, records);
|
|
175
|
+
const source = domain.providerMessageSource === "certificate_authority" ? "certificate_authority" : "hostname";
|
|
176
|
+
// A hostname's own note while the owner is still publishing records is the expected "does not
|
|
177
|
+
// CNAME to this zone": it says nothing the records table does not, so it is not surfaced there.
|
|
178
|
+
const showMessage = Boolean(domain.providerMessage && domain.providerMessageAt) && state !== "live" && !(source === "hostname" && state === "waiting_for_dns");
|
|
179
|
+
const withMessage = (code) => showMessage ? { code, providerMessage: { text: domain.providerMessage, seenAt: domain.providerMessageAt, source } } : { code };
|
|
180
|
+
const nextCheckAt = options.nextCheckAt ? { nextCheckAt: options.nextCheckAt } : {};
|
|
181
|
+
const required = records.filter((record) => !record.optional);
|
|
182
|
+
if (state === "expired")
|
|
183
|
+
return { state, reason: withMessage("expired"), next: { who: "owner", action: "add_again" } };
|
|
184
|
+
if (state === "live")
|
|
185
|
+
return { state, reason: null, next: { action: "none" } };
|
|
186
|
+
if (state === "failed") {
|
|
187
|
+
const error = domain.provisioningError;
|
|
188
|
+
if (isServiceModeProvisioningError(error)) {
|
|
189
|
+
return { state, reason: withMessage("service_mode"), next: { who: "owner", action: "change_access_mode" } };
|
|
190
|
+
}
|
|
191
|
+
if (error === CUSTOM_DOMAINS_NOT_CONFIGURED_MESSAGE) {
|
|
192
|
+
return { state, reason: withMessage("platform_not_configured"), next: { who: "platform", action: "contact_support" } };
|
|
193
|
+
}
|
|
194
|
+
if (error === CUSTOM_DOMAIN_ROUTE_CONFLICT_MESSAGE) {
|
|
195
|
+
return { state, reason: withMessage("claimed_elsewhere"), next: { who: "platform", action: "contact_support" } };
|
|
196
|
+
}
|
|
197
|
+
if (!error && domain.tlsStatus === "failed") {
|
|
198
|
+
const fix = required.filter((record) => record.ok === false).map(nextRecord);
|
|
199
|
+
return {
|
|
200
|
+
state,
|
|
201
|
+
reason: withMessage("certificate_failed"),
|
|
202
|
+
next: { who: "owner", action: "start_over", ...(fix.length > 0 ? { records: fix } : {}) },
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (!error) {
|
|
206
|
+
// Routing failed with nothing recorded to say why. Nothing measured says the owner can
|
|
207
|
+
// fix it, so DNS edits are not prescribed: support is, and Re-check stays available.
|
|
208
|
+
return { state, reason: withMessage("hostname_failed"), next: { who: "platform", action: "contact_support" } };
|
|
209
|
+
}
|
|
210
|
+
// An upstream call threw; the background reconcile retries it, and Re-check retries now.
|
|
211
|
+
return { state, reason: withMessage("provider_error"), next: { who: "platform", action: "recheck" } };
|
|
212
|
+
}
|
|
213
|
+
const www = rootUnsupportedWwwHostname(domain);
|
|
214
|
+
if (www) {
|
|
215
|
+
return { state, reason: withMessage("dns_host_cannot_point_root"), next: { who: "owner", action: "use_www", hostname: www } };
|
|
216
|
+
}
|
|
217
|
+
if (state === "waiting_for_dns" || state === "dns_unverified") {
|
|
218
|
+
const wrong = required.filter((record) => record.ok === false);
|
|
219
|
+
if (wrong.length > 0) {
|
|
220
|
+
// TXT is never "replace": a name may hold several TXT values, so a missing one is added beside them.
|
|
221
|
+
const pointsElsewhere = wrong.some((record) => record.type !== "TXT" && record.check === "different");
|
|
222
|
+
const code = domain.activatedAt
|
|
223
|
+
? "dns_changed_after_live"
|
|
224
|
+
: pointsElsewhere
|
|
225
|
+
? "record_points_elsewhere"
|
|
226
|
+
: "records_missing";
|
|
227
|
+
return {
|
|
228
|
+
state,
|
|
229
|
+
reason: withMessage(code),
|
|
230
|
+
next: { who: "owner", action: pointsElsewhere ? "replace_record" : "add_records", records: wrong.map(nextRecord), ...nextCheckAt },
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const routingActive = domain.routingStatus === "active";
|
|
234
|
+
const unproven = required.filter((record) => isUnproven(record, routingActive));
|
|
235
|
+
const code = unproven.length > 0 && unproven.every((record) => record.check === "apex_addresses") ? "apex_unverifiable" : "dns_not_checked";
|
|
236
|
+
return {
|
|
237
|
+
state,
|
|
238
|
+
reason: withMessage(code),
|
|
239
|
+
next: { who: "owner", action: "confirm_records", ...(unproven.length > 0 ? { records: unproven.map(nextRecord) } : {}), ...nextCheckAt },
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// issuing_certificate: every required record was checked and found.
|
|
243
|
+
const caa = domain.dnsCheck?.caa;
|
|
244
|
+
if (caa?.status === "blocks" && caa.recordName) {
|
|
245
|
+
return { state, reason: withMessage("caa_blocks"), next: caaNext({ ...caa, recordName: caa.recordName }) };
|
|
246
|
+
}
|
|
247
|
+
return { state, reason: withMessage("certificate_pending"), next: { who: "platform", action: "wait", ...nextCheckAt } };
|
|
248
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Agent } from "undici";
|
|
3
|
+
import { type DomainNext, type DomainReason, type DomainRecordStatus, type DomainState, type DomainStateDnsCheck, type DomainStateDnsInstruction, type DomainStateInput } from "./domain-state.js";
|
|
3
4
|
import type { AccessGrant, AccessGrantType, AccessProviderKey, AppAccessSettings, AppAccessServiceToken, AppAccessToken, AppDatabase, AppRuntime, AppUserFilesUsage, ContainerImageUploadInstruction, ContainerRegion, Deployment, ManagedFileObject, ManagedFileShare, ManagedFileUsage, Project } from "./cli-types.js";
|
|
4
5
|
export interface DeployOptions {
|
|
5
6
|
directory: string;
|
|
@@ -106,6 +107,7 @@ export interface DeletedSiteResult {
|
|
|
106
107
|
slug: string;
|
|
107
108
|
workers: number;
|
|
108
109
|
customDomains: number;
|
|
110
|
+
customDomainNames?: string[];
|
|
109
111
|
containerApplications?: number;
|
|
110
112
|
containerImages?: number;
|
|
111
113
|
accessApps: number;
|
|
@@ -125,7 +127,7 @@ export interface CreatedServiceToken {
|
|
|
125
127
|
clientSecret: string;
|
|
126
128
|
}
|
|
127
129
|
export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
128
|
-
export declare const CLI_VERSION = "0.
|
|
130
|
+
export declare const CLI_VERSION = "0.78.0";
|
|
129
131
|
type CredentialBackend = "macos-keychain" | "windows-dpapi" | "linux-secret-service" | "file-plaintext" | "none";
|
|
130
132
|
export interface StoredCredentialEntry {
|
|
131
133
|
token: string;
|
|
@@ -491,6 +493,7 @@ export declare function dashboardUrlForApiUrl(apiUrl: string): string;
|
|
|
491
493
|
type CliCommand = {
|
|
492
494
|
kind: "deploy";
|
|
493
495
|
options: DeployOptions;
|
|
496
|
+
apiUrlFrom: ApiUrlSource;
|
|
494
497
|
} | {
|
|
495
498
|
kind: "version";
|
|
496
499
|
} | {
|
|
@@ -621,6 +624,7 @@ type CliCommand = {
|
|
|
621
624
|
} | {
|
|
622
625
|
kind: "domains";
|
|
623
626
|
owner?: string;
|
|
627
|
+
apiUrlFrom: ApiUrlSource;
|
|
624
628
|
action: {
|
|
625
629
|
kind: "list";
|
|
626
630
|
site?: string;
|
|
@@ -729,64 +733,52 @@ export declare function deploymentsListJson<T extends ListedDeployment>(deployme
|
|
|
729
733
|
serving: boolean;
|
|
730
734
|
}>;
|
|
731
735
|
};
|
|
732
|
-
export
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
export interface CliDomainDnsCheck {
|
|
739
|
-
provider: string | null;
|
|
740
|
-
nameservers: string[];
|
|
741
|
-
records: Array<{
|
|
742
|
-
type: string;
|
|
743
|
-
host: string;
|
|
744
|
-
expected: string;
|
|
745
|
-
current: string[];
|
|
746
|
-
matches: boolean;
|
|
736
|
+
export { CUSTOM_DOMAIN_EXPIRED_TEXT, deriveDomainState, deriveDomainStatus, domainRecordStatuses, type DomainRecordCheck, type DomainRecordStatus, type DomainState, } from "./domain-state.js";
|
|
737
|
+
export type CliDnsInstruction = DomainStateDnsInstruction;
|
|
738
|
+
export type CliDomainDnsCheck = DomainStateDnsCheck & {
|
|
739
|
+
advisories?: Array<{
|
|
740
|
+
code: string;
|
|
741
|
+
message: string;
|
|
747
742
|
}>;
|
|
748
|
-
}
|
|
749
|
-
export interface CliDomain {
|
|
750
|
-
|
|
751
|
-
routingStatus: string;
|
|
752
|
-
tlsStatus: string;
|
|
753
|
-
dnsInstructions: CliDnsInstruction[];
|
|
754
|
-
provisioningError: string | null;
|
|
743
|
+
};
|
|
744
|
+
export interface CliDomain extends DomainStateInput {
|
|
745
|
+
dnsCheck?: CliDomainDnsCheck;
|
|
755
746
|
expireAfter?: string | null;
|
|
756
747
|
expiresAt?: string | null;
|
|
757
|
-
dnsCheck?: CliDomainDnsCheck;
|
|
758
748
|
app?: {
|
|
759
749
|
id: string;
|
|
760
750
|
slug: string;
|
|
761
751
|
name: string;
|
|
762
752
|
};
|
|
753
|
+
state?: string;
|
|
754
|
+
reason?: DomainReason | null;
|
|
755
|
+
next?: DomainNext;
|
|
756
|
+
}
|
|
757
|
+
export interface DomainRecordStatusJson extends DomainRecordStatus {
|
|
758
|
+
typeAtProvider: string | null;
|
|
759
|
+
nameAtProvider: string;
|
|
760
|
+
valueAtProvider: string;
|
|
763
761
|
}
|
|
764
|
-
export type DomainState = "live" | "waiting_for_dns" | "dns_unverified" | "issuing_certificate" | "failed" | "expired";
|
|
765
|
-
export declare const CUSTOM_DOMAIN_EXPIRED_TEXT = "This domain was removed because its DNS verification was never completed. Add the domain again to retry.";
|
|
766
|
-
export interface DomainRecordStatus {
|
|
767
|
-
type: string;
|
|
768
|
-
name: string;
|
|
769
|
-
fqdn: string;
|
|
770
|
-
expected: string;
|
|
771
|
-
current: string[] | null;
|
|
772
|
-
ok: boolean | null;
|
|
773
|
-
check: DomainRecordCheck;
|
|
774
|
-
apex: boolean;
|
|
775
|
-
optional: boolean;
|
|
776
|
-
}
|
|
777
|
-
export type DomainRecordCheck = "found" | "missing" | "different" | "not_checked" | "apex_addresses";
|
|
778
762
|
export interface DomainStatusJson {
|
|
779
763
|
hostname: string;
|
|
780
764
|
app: string;
|
|
781
|
-
state: DomainState;
|
|
765
|
+
state: DomainState | (string & {});
|
|
782
766
|
routing: string;
|
|
783
767
|
tls: string;
|
|
784
768
|
provider: string | null;
|
|
769
|
+
providerId: string | null;
|
|
785
770
|
nameservers: string[];
|
|
786
|
-
|
|
771
|
+
zone: string | null;
|
|
772
|
+
records: DomainRecordStatusJson[];
|
|
773
|
+
advisories: Array<{
|
|
774
|
+
code: string;
|
|
775
|
+
message: string;
|
|
776
|
+
}>;
|
|
787
777
|
error: string | null;
|
|
788
778
|
expiresAt: string | null;
|
|
789
779
|
checkedAt: string;
|
|
780
|
+
reason: DomainReason | null;
|
|
781
|
+
next: DomainNext;
|
|
790
782
|
}
|
|
791
783
|
export declare const DOMAIN_WAIT_EXIT: {
|
|
792
784
|
readonly live: 0;
|
|
@@ -794,13 +786,15 @@ export declare const DOMAIN_WAIT_EXIT: {
|
|
|
794
786
|
readonly platform: 11;
|
|
795
787
|
readonly failed: 20;
|
|
796
788
|
};
|
|
797
|
-
export declare function domainRecordStatuses(domain: CliDomain): DomainRecordStatus[];
|
|
798
|
-
export declare function deriveDomainState(domain: CliDomain, records?: DomainRecordStatus[]): DomainState;
|
|
799
789
|
export declare function domainStatusJson(domain: CliDomain, app: string, checkedAt: string): DomainStatusJson;
|
|
800
|
-
export declare function domainStateLabel(state:
|
|
801
|
-
export declare function
|
|
790
|
+
export declare function domainStateLabel(state: string): string;
|
|
791
|
+
export declare function domainWaitExitCode(status: Pick<DomainStatusJson, "state" | "next">): number;
|
|
792
|
+
export interface DomainFormatOptions {
|
|
802
793
|
owner?: string;
|
|
803
|
-
|
|
794
|
+
target?: AccessApiTarget;
|
|
795
|
+
}
|
|
796
|
+
export declare const DNS_PROVIDER_NOTES: Record<string, string>;
|
|
797
|
+
export declare function formatDomainStatus(status: DomainStatusJson, options?: DomainFormatOptions): string[];
|
|
804
798
|
export declare function domainWaitTimeoutMessage(status: DomainStatusJson): string;
|
|
805
799
|
export declare function formatDomainsList(statuses: DomainStatusJson[]): string[];
|
|
806
800
|
export declare class DomainsApiError extends Error {
|
|
@@ -838,6 +832,14 @@ export declare function restartDomain(options: DomainCommandOptions & {
|
|
|
838
832
|
export declare function removeDomain(options: DomainCommandOptions & {
|
|
839
833
|
hostname: string;
|
|
840
834
|
}): Promise<CliDomain | null>;
|
|
835
|
+
export declare const DEPLOY_DOMAINS_TIMEOUT_MS = 4500;
|
|
836
|
+
export declare function deployCustomDomainStatuses(options: ApiOptions & {
|
|
837
|
+
projectId: string;
|
|
838
|
+
slug: string;
|
|
839
|
+
timeoutMs?: number;
|
|
840
|
+
now?: () => Date;
|
|
841
|
+
}): Promise<DomainStatusJson[] | null>;
|
|
842
|
+
export declare function deployCustomDomainLines(statuses: DomainStatusJson[] | null, slug: string, owner?: string, target?: AccessApiTarget): string[];
|
|
841
843
|
export interface DomainWaitResult {
|
|
842
844
|
status: DomainStatusJson;
|
|
843
845
|
exitCode: number;
|
|
@@ -898,5 +900,5 @@ export interface AccessApiTarget {
|
|
|
898
900
|
apiUrl: string;
|
|
899
901
|
apiUrlFrom: ApiUrlSource;
|
|
900
902
|
}
|
|
903
|
+
export declare function apiUrlFlagFor(target?: AccessApiTarget): string;
|
|
901
904
|
export declare function accessSwitchModeCommand(action: AccessModeChangeAction, target?: AccessApiTarget): string;
|
|
902
|
-
export {};
|