wawesome 0.15.0 → 0.16.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 +27 -6
- package/dist/index.mjs +181 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,6 +118,7 @@ npx wawesome deploy
|
|
|
118
118
|
| `npx wawesome env set <key> <val>` | Set an environment variable (add `--secret` for write-only) |
|
|
119
119
|
| `npx wawesome env rm <key>` | Delete an environment variable |
|
|
120
120
|
| `npx wawesome domains` | Show the app's domain, its state, and the DNS records to add |
|
|
121
|
+
| `npx wawesome domains adopt` | Write the domain the app answers at into wawesome-function.json |
|
|
121
122
|
| `npx wawesome domains detach <host>` | Stop serving the app at a domain you attached |
|
|
122
123
|
| `npx wawesome credentials` | List deploy credentials: name, prefix, capabilities, Apps, last use |
|
|
123
124
|
| `npx wawesome credentials mint <name>` | Mint a deploy credential and print its secret, once |
|
|
@@ -493,6 +494,9 @@ concluding the platform cannot do it.
|
|
|
493
494
|
| `deploy_status` | How a deploy went, by the handle it answered with | `read:functions` |
|
|
494
495
|
| `rollback_function` | Puts a Version the Function already has back on its public address | `write:functions` |
|
|
495
496
|
| `set_env_var` | Sets an App's environment variable, read at the next invocation | `write:env` |
|
|
497
|
+
| `attach_domain` | Attaches a domain to an App and answers the DNS records that make it work | `write:domains` |
|
|
498
|
+
| `cancel_domain_claim` | Gives up a domain claim nobody has proved control of, freeing the App's place | `write:domains` |
|
|
499
|
+
| `check_domain` | Where the domain attached to an App got to, asked at the certificate vendor | `read:domains` |
|
|
496
500
|
| `invoke_function` | Runs a deployed Function once and answers with the Invocation id | `write:runs` |
|
|
497
501
|
| `fetch_function` | Fetches one path from a Function's live Version and answers what it served | `write:runs` |
|
|
498
502
|
|
|
@@ -553,7 +557,9 @@ npx wawesome credentials mint ci --preset deployer -a prod
|
|
|
553
557
|
npx wawesome credentials mint agent --preset member -a prod
|
|
554
558
|
```
|
|
555
559
|
|
|
556
|
-
Add `write:domains` where the project declares a custom domain the deploy should claim
|
|
560
|
+
Add `write:domains` where the project declares a custom domain the deploy should claim, or where an
|
|
561
|
+
agent attaches one for somebody who has no terminal — it also gives back a claim nobody has proved
|
|
562
|
+
control of yet, and never takes a live name off an App. Nothing gives
|
|
557
563
|
an agent billing, a plan change, credential management or the ability to rename your workspace: those
|
|
558
564
|
are closed to every credential, whatever it carries. Reading the workspace's name and address is not
|
|
559
565
|
among them — `whoami` answers both to any credential, which is how the agent knows where what it
|
|
@@ -812,13 +818,27 @@ deploy prints the refusal and lands everything else it was doing.
|
|
|
812
818
|
The address derived from your workspace slug keeps serving after you attach a domain. Both names
|
|
813
819
|
answer, so webhooks and integrations already pointed at the old one keep working.
|
|
814
820
|
|
|
815
|
-
An apex domain, `client.com` with no `www`,
|
|
816
|
-
|
|
817
|
-
|
|
821
|
+
An apex domain, `client.com` with no `www`, claims `www.client.com` with it, and attaching the `www`
|
|
822
|
+
claims the apex. Both halves are one domain against your App's one place, and both are printed with
|
|
823
|
+
their own state and their own records, because a visitor typing either one should reach your site.
|
|
824
|
+
Where your DNS provider cannot hold a CNAME at your zone root, that half is reported as not claimed
|
|
825
|
+
with the reason, and attaching the same name again picks it up once your DNS can carry it.
|
|
826
|
+
|
|
827
|
+
The file is not the only door. A domain can also be attached from the dashboard or by an agent, and
|
|
828
|
+
then your App answers at a name `wawesome-function.json` has never heard of. A deploy says so and
|
|
829
|
+
edits nothing — what was committed is what ships — so the file is written by a command of your own:
|
|
830
|
+
|
|
831
|
+
```bash
|
|
832
|
+
npx wawesome domains adopt
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
It writes the attached hostname into `wawesome-function.json` and changes nothing about the domain.
|
|
836
|
+
Where the file already declares a *different* name, it refuses and prints both: an App carries one
|
|
837
|
+
domain, and which of the two names it should be is yours to settle rather than a file to overwrite.
|
|
818
838
|
|
|
819
839
|
Deleting the line detaches nothing. Detaching takes a live site dark, which is not something a
|
|
820
840
|
deploy should infer from a deleted line. So the deploy reports the domain it found and left serving,
|
|
821
|
-
and names the one command that takes it off:
|
|
841
|
+
names the command that writes it into the file, and names the one command that takes it off:
|
|
822
842
|
|
|
823
843
|
```bash
|
|
824
844
|
npx wawesome domains detach shop.client.com
|
|
@@ -837,7 +857,7 @@ handler sees it, and off your response before the caller does. So **do not name
|
|
|
837
857
|
own on that prefix**. It is dropped silently rather than rejected, and you will not get an error
|
|
838
858
|
telling you why it vanished.
|
|
839
859
|
|
|
840
|
-
|
|
860
|
+
Five headers arrive or leave on it, and the stripping is what makes them worth trusting:
|
|
841
861
|
|
|
842
862
|
| Header | Direction | What it means |
|
|
843
863
|
| --- | --- | --- |
|
|
@@ -845,6 +865,7 @@ Four headers arrive or leave on it, and the stripping is what makes them worth t
|
|
|
845
865
|
| `x-wawesome-trigger` | inbound | How this run started: `caller` when someone called your address, `schedule` when fired by a Schedule. A caller cannot forge it in production (stripped inbound). On the local development surface, pass `x-wawesome-trigger: schedule` to exercise a background run by hand with the collapsed budget. |
|
|
846
866
|
| `x-wawesome-invocation-id` | outbound | The id of this run, the key to fetch its logs with `npx wawesome logs --invocation <id>`. |
|
|
847
867
|
| `x-wawesome-error` | outbound | Present only when the platform failed, never when your Function did. Its *absence* means the status on the wire is yours, up to the moment your response is committed and no further. |
|
|
868
|
+
| `x-wawesome-document` | outbound | Set it to the path of a document your own deploy carried (`index.html`) and the platform streams that file in place of the body you returned. Your status and your other headers stand; the content type and the length are the file's. Naming a path your deploy does not carry is a `500`, and your logs say which path you named. |
|
|
848
869
|
|
|
849
870
|
### Testing against the guest's JavaScript surface
|
|
850
871
|
|
package/dist/index.mjs
CHANGED
|
@@ -232,12 +232,11 @@ function deleteCredentials() {
|
|
|
232
232
|
}
|
|
233
233
|
return false;
|
|
234
234
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
function getFunctionConfigPath(projectDir) {
|
|
236
|
+
return path.join(projectDir || process.cwd(), "wawesome-function.json");
|
|
237
|
+
}
|
|
238
238
|
function readFunctionConfig(projectDir) {
|
|
239
|
-
const
|
|
240
|
-
const configPath = path.join(dir, "wawesome-function.json");
|
|
239
|
+
const configPath = getFunctionConfigPath(projectDir);
|
|
241
240
|
if (!fs.existsSync(configPath)) return null;
|
|
242
241
|
try {
|
|
243
242
|
const raw = fs.readFileSync(configPath, "utf-8");
|
|
@@ -906,7 +905,7 @@ async function buildHandler(entryInput, config, options) {
|
|
|
906
905
|
* that has to name this version — `--version`, the dependency a scaffolded
|
|
907
906
|
* project pins — reads it here, so a release bumps one file.
|
|
908
907
|
*/
|
|
909
|
-
const CLI_VERSION = "0.
|
|
908
|
+
const CLI_VERSION = "0.16.0";
|
|
910
909
|
//#endregion
|
|
911
910
|
//#region src/prompt.ts
|
|
912
911
|
/**
|
|
@@ -1579,7 +1578,7 @@ async function applyDeclaredDomain(creds, app, hostname) {
|
|
|
1579
1578
|
said: whatWentWrong(err)
|
|
1580
1579
|
};
|
|
1581
1580
|
}
|
|
1582
|
-
const attached = held.find((domain) =>
|
|
1581
|
+
const attached = held.find((domain) => carries(domain, hostname));
|
|
1583
1582
|
if (attached) return {
|
|
1584
1583
|
kind: "unchanged",
|
|
1585
1584
|
domain: attached
|
|
@@ -1631,6 +1630,15 @@ function whatWentWrong(err) {
|
|
|
1631
1630
|
return errorText(err);
|
|
1632
1631
|
}
|
|
1633
1632
|
/**
|
|
1633
|
+
* Whether a claim answers at the declared name — at the leg it reads as, or at
|
|
1634
|
+
* the other half it carries. A file naming the `www` of an apex-led claim
|
|
1635
|
+
* declares a name the App already answers at, and re-attaching it every deploy
|
|
1636
|
+
* would report a change nothing made.
|
|
1637
|
+
*/
|
|
1638
|
+
function carries(domain, declared) {
|
|
1639
|
+
return [domain.hostname, ...(domain.legs ?? []).filter((leg) => leg.claimed).map((leg) => leg.hostname)].some((name) => isSameHostname(name, declared));
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1634
1642
|
* The comparison the platform makes: a name is held lowercase without its
|
|
1635
1643
|
* trailing dot, so `shop.client.com.` in the file is the domain already
|
|
1636
1644
|
* attached rather than a second one to ask for on every deploy.
|
|
@@ -1722,6 +1730,105 @@ async function detachDomainCommand(hostname, options = {}) {
|
|
|
1722
1730
|
}
|
|
1723
1731
|
}
|
|
1724
1732
|
/**
|
|
1733
|
+
* The project's configuration as a file to write rather than as settings to
|
|
1734
|
+
* read: the raw text, so what is written back keeps the shape of what was
|
|
1735
|
+
* committed, and a file that does not parse is refused rather than replaced.
|
|
1736
|
+
*/
|
|
1737
|
+
function projectConfig() {
|
|
1738
|
+
const path = getFunctionConfigPath();
|
|
1739
|
+
if (!fs.existsSync(path)) {
|
|
1740
|
+
console.error("[wawesome] Error: No wawesome-function.json found in the current directory.");
|
|
1741
|
+
console.error("[wawesome] Run this from the project that deploys the app.");
|
|
1742
|
+
process.exit(1);
|
|
1743
|
+
}
|
|
1744
|
+
const text = fs.readFileSync(path, "utf-8");
|
|
1745
|
+
try {
|
|
1746
|
+
return {
|
|
1747
|
+
path,
|
|
1748
|
+
text,
|
|
1749
|
+
parsed: JSON.parse(text)
|
|
1750
|
+
};
|
|
1751
|
+
} catch (err) {
|
|
1752
|
+
console.error(`[wawesome] Error: wawesome-function.json is not valid JSON: ${errorText(err)}`);
|
|
1753
|
+
console.error("[wawesome] Nothing was written. Fix the file and run this again.");
|
|
1754
|
+
process.exit(1);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* The declared domain written back, in the indentation the file already uses so
|
|
1759
|
+
* the diff is the one line.
|
|
1760
|
+
*/
|
|
1761
|
+
function writeDeclaredDomain(config, hostname) {
|
|
1762
|
+
const indent = /\n([ \t]+)"/.exec(config.text)?.[1] ?? " ";
|
|
1763
|
+
const written = JSON.stringify({
|
|
1764
|
+
...config.parsed,
|
|
1765
|
+
domain: hostname
|
|
1766
|
+
}, null, indent);
|
|
1767
|
+
fs.writeFileSync(config.path, config.text.endsWith("\n") ? `${written}\n` : written, "utf-8");
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Write the domain the App carries into wawesome-function.json.
|
|
1771
|
+
*
|
|
1772
|
+
* The fix named beside the drift a deploy reports (ADR-0034). The platform row
|
|
1773
|
+
* is what serves and the file is a desired state, so a name attached from the
|
|
1774
|
+
* dashboard or by an agent is a name this file has never heard of — and a
|
|
1775
|
+
* deploy will not write it, because a deploy never edits a tracked file.
|
|
1776
|
+
*
|
|
1777
|
+
* A file naming a different domain is two names in play and a person's
|
|
1778
|
+
* question: both are printed and nothing is written.
|
|
1779
|
+
*/
|
|
1780
|
+
async function adoptDomainCommand(hostname, options = {}) {
|
|
1781
|
+
if (hostname?.trim()) {
|
|
1782
|
+
console.error(`[wawesome] Error: 'wawesome domains adopt' takes no hostname, and '${hostname.trim()}' was given.`);
|
|
1783
|
+
console.error("[wawesome] It writes the name the app already answers at, which it reads from the platform.");
|
|
1784
|
+
process.exit(1);
|
|
1785
|
+
}
|
|
1786
|
+
const config = projectConfig();
|
|
1787
|
+
const { creds, app } = credentialsAndApp(options);
|
|
1788
|
+
const deploysTo = typeof config.parsed.app === "string" ? config.parsed.app.trim() : void 0;
|
|
1789
|
+
if (deploysTo && deploysTo !== app) {
|
|
1790
|
+
console.error(`[wawesome] Error: wawesome-function.json deploys to app '${deploysTo}', and --app names '${app}'.`);
|
|
1791
|
+
console.error("[wawesome] Nothing was written: a name off another app does not belong in this file.");
|
|
1792
|
+
process.exit(1);
|
|
1793
|
+
}
|
|
1794
|
+
let held;
|
|
1795
|
+
try {
|
|
1796
|
+
held = await listDomains(creds, app);
|
|
1797
|
+
} catch (err) {
|
|
1798
|
+
console.error(`[wawesome] Error: ${whatWentWrong(err)}`);
|
|
1799
|
+
process.exit(1);
|
|
1800
|
+
}
|
|
1801
|
+
const attached = held.find((domain) => !domain.detaching);
|
|
1802
|
+
if (!attached) {
|
|
1803
|
+
console.log(`[wawesome] No domain is attached to app '${app}', so there is nothing to adopt.`);
|
|
1804
|
+
console.log(held.length > 0 ? "[wawesome] The one it carried is being detached." : "[wawesome] Attach one from the dashboard, from an agent, or by declaring it here and deploying.");
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
const declared = declaredDomain(config.parsed.domain);
|
|
1808
|
+
if (declared && carries(attached, declared)) {
|
|
1809
|
+
console.log(`[wawesome] wawesome-function.json already declares '${declared}'.`);
|
|
1810
|
+
console.log(`[wawesome] App '${app}' answers at it, so nothing was written.`);
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
if (declared) {
|
|
1814
|
+
console.error(`[wawesome] Error: Two domains are in play on app '${app}'.`);
|
|
1815
|
+
console.error(`[wawesome] wawesome-function.json declares '${declared}'`);
|
|
1816
|
+
console.error(`[wawesome] the app answers at '${attached.hostname}'`);
|
|
1817
|
+
console.error("[wawesome] Nothing was written. An App carries one domain, so which of the two");
|
|
1818
|
+
console.error("[wawesome] it is is yours to settle: edit the line yourself, or take the attached");
|
|
1819
|
+
console.error("[wawesome] one off with");
|
|
1820
|
+
console.error(`[wawesome] \x1b[36mwawesome domains detach ${attached.hostname}\x1b[0m`);
|
|
1821
|
+
console.error("[wawesome] and deploy to attach the declared one.");
|
|
1822
|
+
process.exit(1);
|
|
1823
|
+
}
|
|
1824
|
+
writeDeclaredDomain(config, attached.hostname);
|
|
1825
|
+
console.log(`[wawesome] wawesome-function.json now declares '${attached.hostname}'.`);
|
|
1826
|
+
const answersAt = claimedHostnames(attached);
|
|
1827
|
+
if (answersAt.length > 1) console.log(`[wawesome] The app answers at both halves of the name: ${answersAt.join(", ")}.`);
|
|
1828
|
+
console.log("[wawesome] Nothing about the domain changed: it was attached already, and the file");
|
|
1829
|
+
console.log("[wawesome] now says so. Commit it, and every deploy from here agrees.");
|
|
1830
|
+
}
|
|
1831
|
+
/**
|
|
1725
1832
|
* What this App answers at, read and printed.
|
|
1726
1833
|
*
|
|
1727
1834
|
* The one place a Tenant can ask. The records used to exist only in the output
|
|
@@ -1752,10 +1859,12 @@ async function showDomainCommand(options = {}) {
|
|
|
1752
1859
|
async function domainsCommand(action, target, options = {}) {
|
|
1753
1860
|
const verb = (action || "").toLowerCase().trim();
|
|
1754
1861
|
if (verb === "detach") return detachDomainCommand(target, options);
|
|
1862
|
+
if (verb === "adopt") return adoptDomainCommand(target, options);
|
|
1755
1863
|
if (!verb) return showDomainCommand(options);
|
|
1756
1864
|
console.error(`[wawesome] Error: Unknown command '${["domains", action].filter(Boolean).join(" ")}'.`);
|
|
1757
|
-
console.error("[wawesome] Usage: wawesome domains [detach <hostname>]");
|
|
1758
|
-
console.error("[wawesome] A domain is attached by declaring it in wawesome-function.json
|
|
1865
|
+
console.error("[wawesome] Usage: wawesome domains [adopt | detach <hostname>]");
|
|
1866
|
+
console.error("[wawesome] A domain is attached by declaring it in wawesome-function.json, from the");
|
|
1867
|
+
console.error("[wawesome] dashboard, or by an agent.");
|
|
1759
1868
|
process.exit(1);
|
|
1760
1869
|
}
|
|
1761
1870
|
function domainsUrl(creds, app) {
|
|
@@ -1809,10 +1918,14 @@ function domainLines(outcome) {
|
|
|
1809
1918
|
if (outcome.kind === "undeclared") {
|
|
1810
1919
|
const { hostname, state } = outcome.domain;
|
|
1811
1920
|
const left = state.serving ? "it is still serving" : "nothing changed";
|
|
1921
|
+
const answersAt = claimedHostnames(outcome.domain);
|
|
1812
1922
|
return [
|
|
1813
1923
|
"",
|
|
1814
1924
|
` Domain: \x1b[33m${hostname}: attached, and this project declares no domain\x1b[0m`,
|
|
1815
|
-
...
|
|
1925
|
+
...answersAt.length > 1 ? indented(`Both halves of the name are attached: ${answersAt.join(", ")}.`) : [],
|
|
1926
|
+
...indented(`Nothing was detached and ${left}. A domain comes off an App when somebody names it, never because a line was deleted. To write it into wawesome-function.json, run`),
|
|
1927
|
+
`${VALUE_COLUMN} \x1b[36mwawesome domains adopt\x1b[0m`,
|
|
1928
|
+
...indented("To take it off the App instead, run"),
|
|
1816
1929
|
`${VALUE_COLUMN} \x1b[36mwawesome domains detach ${hostname}\x1b[0m`
|
|
1817
1930
|
];
|
|
1818
1931
|
}
|
|
@@ -1843,21 +1956,73 @@ function attachedDomainLines(domain, printedBy = "deploy") {
|
|
|
1843
1956
|
`${VALUE_COLUMN}Remove 'domain' from wawesome-function.json, or deploy again`,
|
|
1844
1957
|
`${VALUE_COLUMN}once it is gone to attach it afresh.`
|
|
1845
1958
|
];
|
|
1959
|
+
const legs = domain.legs ?? [];
|
|
1960
|
+
if (legs.length > 1) return pairLines(domain, legs, printedBy);
|
|
1846
1961
|
const lines = ["", ` Domain: \x1b[36m${hostname}\x1b[0m: ${whereItGotTo(domain)}`];
|
|
1847
1962
|
if (last_checked_at) lines.push(`${VALUE_COLUMN}Last checked ${asUtc$1(last_checked_at)}.`);
|
|
1848
1963
|
if (state.serving) {
|
|
1849
1964
|
lines.push(`${VALUE_COLUMN}This app's own address answers too, so nothing pointed at it breaks.`);
|
|
1850
1965
|
return lines;
|
|
1851
1966
|
}
|
|
1852
|
-
const nameWidth = Math.max(...records.map((record) => record.name.length));
|
|
1853
|
-
const row = (type, name, value = "") => ` ${type.padEnd(5)} ${name.padEnd(nameWidth)} ${value}`.trimEnd();
|
|
1854
1967
|
lines.push("", " DNS records to add at your registrar:");
|
|
1855
|
-
|
|
1856
|
-
for (const record of records) lines.push("", ` ${whatItIsFor(record.purpose)}:`, row(record.type, record.name, record.value));
|
|
1968
|
+
lines.push(...recordLines(records, certificate_record_pending, " "));
|
|
1857
1969
|
lines.push("", ...closingLines(certificate_record_pending, printedBy));
|
|
1858
1970
|
return lines;
|
|
1859
1971
|
}
|
|
1860
1972
|
/**
|
|
1973
|
+
* A claim carrying both halves of a name: where the claim got to, then each leg
|
|
1974
|
+
* with its own state and its own records.
|
|
1975
|
+
*
|
|
1976
|
+
* Every leg is named, the half nothing claimed included. Four records to add
|
|
1977
|
+
* rather than two is the cost of a name that answers at both halves, and a leg
|
|
1978
|
+
* left out of this block is a record nobody adds on the name a visitor typed.
|
|
1979
|
+
*/
|
|
1980
|
+
function pairLines(domain, legs, printedBy) {
|
|
1981
|
+
const lines = ["", ` Domain: \x1b[36m${domain.hostname}\x1b[0m: ${domain.state.serving ? "serving at both halves of the name" : "coming up, and each half of the name is below"}`];
|
|
1982
|
+
if (domain.last_checked_at) lines.push(`${VALUE_COLUMN}Last checked ${asUtc$1(domain.last_checked_at)}.`);
|
|
1983
|
+
lines.push("");
|
|
1984
|
+
for (const leg of legs) {
|
|
1985
|
+
lines.push(`${VALUE_COLUMN}${leg.hostname}: ${whereTheLegGotTo(leg)}`);
|
|
1986
|
+
if (leg.unclaimed_reason) lines.push(...wrapped(leg.unclaimed_reason).map((line) => `${VALUE_COLUMN} ${line}`));
|
|
1987
|
+
}
|
|
1988
|
+
const outstanding = legs.filter((leg) => leg.claimed && !leg.state.serving);
|
|
1989
|
+
if (outstanding.length === 0) {
|
|
1990
|
+
lines.push(`${VALUE_COLUMN}This app's own address answers too, so nothing pointed at it breaks.`);
|
|
1991
|
+
return lines;
|
|
1992
|
+
}
|
|
1993
|
+
lines.push("", " DNS records to add at your registrar:");
|
|
1994
|
+
for (const leg of outstanding) {
|
|
1995
|
+
lines.push("", ` ${leg.hostname}:`);
|
|
1996
|
+
lines.push(...recordLines(leg.records ?? [], leg.certificate_record_pending, " "));
|
|
1997
|
+
}
|
|
1998
|
+
const pending = outstanding.some((leg) => leg.certificate_record_pending);
|
|
1999
|
+
lines.push("", ...closingLines(pending, printedBy));
|
|
2000
|
+
return lines;
|
|
2001
|
+
}
|
|
2002
|
+
function whereTheLegGotTo(leg) {
|
|
2003
|
+
return leg.claimed ? whereItGotTo(leg) : "not claimed";
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* The records one leg is waiting on, each under what it is for.
|
|
2007
|
+
*
|
|
2008
|
+
* What each record is for goes above it rather than beside it. A DCV value is
|
|
2009
|
+
* 40-odd characters a person has to copy exactly, and a fourth column puts the
|
|
2010
|
+
* row past the width of the terminal it is being copied out of.
|
|
2011
|
+
*/
|
|
2012
|
+
function recordLines(records, certificateRecordPending, indent) {
|
|
2013
|
+
const nameWidth = Math.max(0, ...records.map((record) => record.name.length));
|
|
2014
|
+
const row = (type, name, value = "") => `${indent} ${type.padEnd(5)} ${name.padEnd(nameWidth)} ${value}`.trimEnd();
|
|
2015
|
+
const lines = [];
|
|
2016
|
+
if (certificateRecordPending) lines.push("", `${indent}${whatItIsFor("certificate")}:`, row("TXT", "not ready yet"));
|
|
2017
|
+
for (const record of records) lines.push("", `${indent}${whatItIsFor(record.purpose)}:`, row(record.type, record.name, record.value));
|
|
2018
|
+
return lines;
|
|
2019
|
+
}
|
|
2020
|
+
/** Every hostname a claim answers at, for a block naming the claim in one line. */
|
|
2021
|
+
function claimedHostnames(domain) {
|
|
2022
|
+
const claimed = (domain.legs ?? []).filter((leg) => leg.claimed).map((leg) => leg.hostname);
|
|
2023
|
+
return claimed.length > 0 ? claimed : [domain.hostname];
|
|
2024
|
+
}
|
|
2025
|
+
/**
|
|
1861
2026
|
* What is left to do, which is nothing.
|
|
1862
2027
|
*
|
|
1863
2028
|
* The pending case pointed at another deploy until #617: a deploy that changed
|
|
@@ -5767,7 +5932,8 @@ cli.command("env [action] [key] [value]", "Manage environment variables (set, li
|
|
|
5767
5932
|
cli.command("env set <key> <value>", "Set or overwrite an environment variable on the current app").option("-s, --secret", "Flag variable as secret (write-only)").option("-v, --verbose", "Enable verbose debug output").action((key, value, options) => setEnvVar(key, value, options));
|
|
5768
5933
|
cli.command("env list", "List environment variables for the current app").alias("env ls").option("-v, --verbose", "Enable verbose debug output").action((options) => listEnvVars(options));
|
|
5769
5934
|
cli.command("env rm <key>", "Delete an environment variable from the current app").alias("env remove").alias("env delete").alias("env unset").option("-v, --verbose", "Enable verbose debug output").action((key, options) => removeEnvVar(key, options));
|
|
5770
|
-
cli.command("domains [action] [hostname]", "Show the custom domain on the current app, its state and its DNS records").usage("domains [action] [hostname]\n\nWith no action, prints the app's domain,
|
|
5935
|
+
cli.command("domains [action] [hostname]", "Show the custom domain on the current app, its state and its DNS records").usage("domains [action] [hostname]\n\nWith no action, prints the app's domain, every half of it, where each got to, when the platform last checked, and the records to add.\n\nActions:\n adopt Write the attached domain into wawesome-function.json\n detach <hostname> Stop serving the app at a domain you attached\n\nA domain is attached by declaring it in wawesome-function.json and deploying, from the dashboard, or by an agent.").example("wawesome domains").example("wawesome domains adopt").example("wawesome domains detach shop.client.com").option("-a, --app <slug>", "App to act on (default: the app in wawesome-function.json)").action((action, hostname, options) => domainsCommand(action, hostname, options));
|
|
5936
|
+
cli.command("domains adopt", "Write the domain the current app answers at into wawesome-function.json").option("-a, --app <slug>", "App to act on (default: the app in wawesome-function.json)").action((options) => adoptDomainCommand(void 0, options));
|
|
5771
5937
|
cli.command("domains detach <hostname>", "Stop serving the current app at a domain you attached").option("-a, --app <slug>", "App to act on (default: the app in wawesome-function.json)").action((hostname, options) => detachDomainCommand(hostname, options));
|
|
5772
5938
|
cli.command("login", "Authenticate with the wawesome.io platform").option("--api <url>", "API URL (default: https://api.wawesome.io)").option("--gateway <url>", "Alias for --api <url>").option("--dashboard <url>", "Dashboard URL (default: https://dashboard.wawesome.io)").option("--provider <name>", "OAuth provider (default: github)").option("--workspace <name>", "Name for the workspace, when signing up without a terminal to prompt").option("--accept-terms", "Accept the terms of service and privacy policy, when signing up without a terminal to prompt").option("-v, --verbose", "Enable verbose debug output").action((options) => login(options));
|
|
5773
5939
|
cli.command("logout", "Clear stored authentication credentials").action(() => logout());
|