@madewithremy/admin 0.1.38 → 0.1.40
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/dist/index.d.ts +342 -10
- package/dist/index.js +106 -7
- package/dist/index.js.map +1 -1
- package/dist/prod.js +309 -13
- package/package.json +1 -1
package/dist/prod.js
CHANGED
|
@@ -274,20 +274,20 @@ function seg(value) {
|
|
|
274
274
|
return encodeURIComponent(String(value));
|
|
275
275
|
}
|
|
276
276
|
function qs(params) {
|
|
277
|
-
const
|
|
277
|
+
const search3 = new URLSearchParams();
|
|
278
278
|
for (const [key, value] of Object.entries(params)) {
|
|
279
279
|
if (value === void 0 || value === null) {
|
|
280
280
|
continue;
|
|
281
281
|
}
|
|
282
282
|
if (Array.isArray(value)) {
|
|
283
283
|
for (const entry of value) {
|
|
284
|
-
|
|
284
|
+
search3.append(key, String(entry));
|
|
285
285
|
}
|
|
286
286
|
continue;
|
|
287
287
|
}
|
|
288
|
-
|
|
288
|
+
search3.set(key, String(value));
|
|
289
289
|
}
|
|
290
|
-
const text =
|
|
290
|
+
const text = search3.toString();
|
|
291
291
|
return text ? `?${text}` : "";
|
|
292
292
|
}
|
|
293
293
|
function authHeaders(ctx) {
|
|
@@ -1510,8 +1510,113 @@ async function customRetry(ctx, hostname) {
|
|
|
1510
1510
|
`/_internal/v2/apps/${ctx.appId}/settings/custom-domains/${seg(id)}/retry`
|
|
1511
1511
|
);
|
|
1512
1512
|
}
|
|
1513
|
+
var REGISTERED = (ctx) => `/_internal/v2/apps/${ctx.appId}/settings/registered-domains`;
|
|
1514
|
+
function search(ctx, query3) {
|
|
1515
|
+
return call(
|
|
1516
|
+
ctx,
|
|
1517
|
+
"POST",
|
|
1518
|
+
`${REGISTERED(ctx)}/search`,
|
|
1519
|
+
{ query: query3 }
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
function quote(ctx, name) {
|
|
1523
|
+
return call(
|
|
1524
|
+
ctx,
|
|
1525
|
+
"POST",
|
|
1526
|
+
`${REGISTERED(ctx)}/quote`,
|
|
1527
|
+
{ name }
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
function buy(ctx, params) {
|
|
1531
|
+
return call(
|
|
1532
|
+
ctx,
|
|
1533
|
+
"POST",
|
|
1534
|
+
`${REGISTERED(ctx)}/purchase`,
|
|
1535
|
+
{ name: params.name, expectedPrice: params.price, acceptTerms: true }
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
function owned(ctx) {
|
|
1539
|
+
return call(ctx, "GET", REGISTERED(ctx));
|
|
1540
|
+
}
|
|
1541
|
+
async function findOwned(ctx, name) {
|
|
1542
|
+
const wanted = name.toLowerCase();
|
|
1543
|
+
const { domains } = await owned(ctx);
|
|
1544
|
+
const domain = domains.find(
|
|
1545
|
+
(d) => d.name === wanted && (d.status === "active" || d.status === "expired" || d.status === "pending")
|
|
1546
|
+
);
|
|
1547
|
+
if (!domain) {
|
|
1548
|
+
throw new Error(`No domain "${name}" in this workspace`);
|
|
1549
|
+
}
|
|
1550
|
+
return domain;
|
|
1551
|
+
}
|
|
1552
|
+
function contactGet(ctx) {
|
|
1553
|
+
return call(
|
|
1554
|
+
ctx,
|
|
1555
|
+
"GET",
|
|
1556
|
+
`${REGISTERED(ctx)}/contact`
|
|
1557
|
+
);
|
|
1558
|
+
}
|
|
1559
|
+
function contactSet(ctx, contact) {
|
|
1560
|
+
return call(
|
|
1561
|
+
ctx,
|
|
1562
|
+
"POST",
|
|
1563
|
+
`${REGISTERED(ctx)}/contact`,
|
|
1564
|
+
{ ...contact }
|
|
1565
|
+
);
|
|
1566
|
+
}
|
|
1567
|
+
async function zone(ctx, name) {
|
|
1568
|
+
const domain = await findOwned(ctx, name);
|
|
1569
|
+
return call(
|
|
1570
|
+
ctx,
|
|
1571
|
+
"GET",
|
|
1572
|
+
`${REGISTERED(ctx)}/${seg(domain.id)}/records`
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
async function zoneAdd(ctx, name, record) {
|
|
1576
|
+
const domain = await findOwned(ctx, name);
|
|
1577
|
+
return call(
|
|
1578
|
+
ctx,
|
|
1579
|
+
"POST",
|
|
1580
|
+
`${REGISTERED(ctx)}/${seg(domain.id)}/records`,
|
|
1581
|
+
{ ...record }
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
async function zoneUpdate(ctx, name, recordId, record) {
|
|
1585
|
+
const domain = await findOwned(ctx, name);
|
|
1586
|
+
return call(
|
|
1587
|
+
ctx,
|
|
1588
|
+
"POST",
|
|
1589
|
+
`${REGISTERED(ctx)}/${seg(domain.id)}/records/${seg(recordId)}`,
|
|
1590
|
+
{ ...record }
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
async function zoneDelete(ctx, name, recordId) {
|
|
1594
|
+
const domain = await findOwned(ctx, name);
|
|
1595
|
+
return call(
|
|
1596
|
+
ctx,
|
|
1597
|
+
"POST",
|
|
1598
|
+
`${REGISTERED(ctx)}/${seg(domain.id)}/records/${seg(recordId)}/delete`
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1513
1601
|
|
|
1514
1602
|
// src/commands/domains.ts
|
|
1603
|
+
var RECORD_TYPES = [
|
|
1604
|
+
"A",
|
|
1605
|
+
"AAAA",
|
|
1606
|
+
"ANAME",
|
|
1607
|
+
"CNAME",
|
|
1608
|
+
"MX",
|
|
1609
|
+
"NS",
|
|
1610
|
+
"SRV",
|
|
1611
|
+
"TXT"
|
|
1612
|
+
];
|
|
1613
|
+
var ZONE_RECORD_FLAGS = {
|
|
1614
|
+
type: { type: "string", choices: RECORD_TYPES },
|
|
1615
|
+
host: { type: "string" },
|
|
1616
|
+
answer: { type: "string" },
|
|
1617
|
+
ttl: { type: "number", min: 300 },
|
|
1618
|
+
priority: { type: "number", min: 0 }
|
|
1619
|
+
};
|
|
1515
1620
|
var domainsSpecs = {
|
|
1516
1621
|
"domains get": {
|
|
1517
1622
|
usage: "Usage: remy-admin domains get"
|
|
@@ -1550,6 +1655,79 @@ var domainsSpecs = {
|
|
|
1550
1655
|
"domains custom retry": {
|
|
1551
1656
|
usage: "Usage: remy-admin domains custom retry <hostname>",
|
|
1552
1657
|
positionals: [{ name: "hostname", required: true }]
|
|
1658
|
+
},
|
|
1659
|
+
"domains search": {
|
|
1660
|
+
usage: "Usage: remy-admin domains search <keyword or name>",
|
|
1661
|
+
positionals: [{ name: "query", required: true, variadic: true }]
|
|
1662
|
+
},
|
|
1663
|
+
"domains quote": {
|
|
1664
|
+
usage: "Usage: remy-admin domains quote <name>",
|
|
1665
|
+
positionals: [{ name: "name", required: true }]
|
|
1666
|
+
},
|
|
1667
|
+
"domains buy": {
|
|
1668
|
+
usage: "Usage: remy-admin domains buy <name> --price <dollars>\nBuys the domain for the workspace at once: the price isn't refundable, and it renews yearly at its renewal price. Only run this after the user has explicitly confirmed the name, the price and the renewal price. --price is the quote's price.",
|
|
1669
|
+
positionals: [{ name: "name", required: true }],
|
|
1670
|
+
flags: {
|
|
1671
|
+
price: { type: "string" }
|
|
1672
|
+
},
|
|
1673
|
+
requireAnyOf: {
|
|
1674
|
+
flags: ["price"],
|
|
1675
|
+
message: "Pass --price with the quote's price the user confirmed (remy-admin domains quote <name>)."
|
|
1676
|
+
}
|
|
1677
|
+
},
|
|
1678
|
+
"domains owned": {
|
|
1679
|
+
usage: "Usage: remy-admin domains owned"
|
|
1680
|
+
},
|
|
1681
|
+
"domains contact get": {
|
|
1682
|
+
usage: "Usage: remy-admin domains contact get"
|
|
1683
|
+
},
|
|
1684
|
+
"domains contact set": {
|
|
1685
|
+
usage: "Usage: remy-admin domains contact set --first-name <n> --last-name <n> [--company <org>] --address1 <line> [--address2 <line>] --city <c> --state <s> --zip <z> --country <XX> --email <e> --phone <+E.164>\nThe registrant: the legal owner of every domain the workspace buys (the organization when --company is set). ICANN emails that address to verify it.",
|
|
1686
|
+
flags: {
|
|
1687
|
+
"first-name": { type: "string" },
|
|
1688
|
+
"last-name": { type: "string" },
|
|
1689
|
+
company: { type: "string" },
|
|
1690
|
+
address1: { type: "string" },
|
|
1691
|
+
address2: { type: "string" },
|
|
1692
|
+
city: { type: "string" },
|
|
1693
|
+
state: { type: "string" },
|
|
1694
|
+
zip: { type: "string" },
|
|
1695
|
+
country: { type: "string" },
|
|
1696
|
+
email: { type: "string" },
|
|
1697
|
+
phone: { type: "string" }
|
|
1698
|
+
}
|
|
1699
|
+
},
|
|
1700
|
+
"domains zone list": {
|
|
1701
|
+
usage: "Usage: remy-admin domains zone list <name>",
|
|
1702
|
+
positionals: [{ name: "name", required: true }]
|
|
1703
|
+
},
|
|
1704
|
+
"domains zone add": {
|
|
1705
|
+
usage: "Usage: remy-admin domains zone add <name> --type <type> --answer <value> [--host <host>] [--ttl <seconds>] [--priority <n>]",
|
|
1706
|
+
positionals: [{ name: "name", required: true }],
|
|
1707
|
+
flags: ZONE_RECORD_FLAGS,
|
|
1708
|
+
requireAnyOf: {
|
|
1709
|
+
flags: ["answer"],
|
|
1710
|
+
message: "Pass --type and --answer."
|
|
1711
|
+
}
|
|
1712
|
+
},
|
|
1713
|
+
"domains zone update": {
|
|
1714
|
+
usage: "Usage: remy-admin domains zone update <name> <recordId> --type <type> --answer <value> [--host <host>] [--ttl <seconds>] [--priority <n>]",
|
|
1715
|
+
positionals: [
|
|
1716
|
+
{ name: "name", required: true },
|
|
1717
|
+
{ name: "recordId", required: true }
|
|
1718
|
+
],
|
|
1719
|
+
flags: ZONE_RECORD_FLAGS,
|
|
1720
|
+
requireAnyOf: {
|
|
1721
|
+
flags: ["answer"],
|
|
1722
|
+
message: "Pass --type and --answer."
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
"domains zone delete": {
|
|
1726
|
+
usage: "Usage: remy-admin domains zone delete <name> <recordId>",
|
|
1727
|
+
positionals: [
|
|
1728
|
+
{ name: "name", required: true },
|
|
1729
|
+
{ name: "recordId", required: true }
|
|
1730
|
+
]
|
|
1553
1731
|
}
|
|
1554
1732
|
};
|
|
1555
1733
|
async function domainsGet(ctx) {
|
|
@@ -1594,6 +1772,72 @@ async function customDomainsRemove(ctx, a) {
|
|
|
1594
1772
|
async function customDomainsRetry(ctx, a) {
|
|
1595
1773
|
out(await customRetry(ctx, a.req("hostname")));
|
|
1596
1774
|
}
|
|
1775
|
+
async function domainsSearch(ctx, a) {
|
|
1776
|
+
out(await search(ctx, a.rest("query").join(" ")));
|
|
1777
|
+
}
|
|
1778
|
+
async function domainsQuote(ctx, a) {
|
|
1779
|
+
out(await quote(ctx, a.req("name")));
|
|
1780
|
+
}
|
|
1781
|
+
async function domainsBuy(ctx, a) {
|
|
1782
|
+
out(
|
|
1783
|
+
await buy(ctx, {
|
|
1784
|
+
name: a.req("name"),
|
|
1785
|
+
price: Number(a.str("price"))
|
|
1786
|
+
})
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
async function domainsOwned(ctx) {
|
|
1790
|
+
out(await owned(ctx));
|
|
1791
|
+
}
|
|
1792
|
+
async function domainsContactGet(ctx) {
|
|
1793
|
+
out(await contactGet(ctx));
|
|
1794
|
+
}
|
|
1795
|
+
async function domainsContactSet(ctx, a) {
|
|
1796
|
+
out(
|
|
1797
|
+
await contactSet(ctx, {
|
|
1798
|
+
firstName: a.str("first-name") ?? "",
|
|
1799
|
+
lastName: a.str("last-name") ?? "",
|
|
1800
|
+
companyName: a.str("company"),
|
|
1801
|
+
address1: a.str("address1") ?? "",
|
|
1802
|
+
address2: a.str("address2"),
|
|
1803
|
+
city: a.str("city") ?? "",
|
|
1804
|
+
state: a.str("state") ?? "",
|
|
1805
|
+
zip: a.str("zip") ?? "",
|
|
1806
|
+
country: a.str("country") ?? "",
|
|
1807
|
+
email: a.str("email") ?? "",
|
|
1808
|
+
phone: a.str("phone") ?? ""
|
|
1809
|
+
})
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
function zoneRecord(a) {
|
|
1813
|
+
const host = a.str("host") ?? "";
|
|
1814
|
+
return {
|
|
1815
|
+
host: host === "@" ? "" : host,
|
|
1816
|
+
type: a.str("type") ?? "",
|
|
1817
|
+
answer: a.str("answer") ?? "",
|
|
1818
|
+
ttl: a.num("ttl"),
|
|
1819
|
+
priority: a.num("priority")
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
async function domainsZoneList(ctx, a) {
|
|
1823
|
+
out(await zone(ctx, a.req("name")));
|
|
1824
|
+
}
|
|
1825
|
+
async function domainsZoneAdd(ctx, a) {
|
|
1826
|
+
out(await zoneAdd(ctx, a.req("name"), zoneRecord(a)));
|
|
1827
|
+
}
|
|
1828
|
+
async function domainsZoneUpdate(ctx, a) {
|
|
1829
|
+
out(
|
|
1830
|
+
await zoneUpdate(
|
|
1831
|
+
ctx,
|
|
1832
|
+
a.req("name"),
|
|
1833
|
+
Number(a.req("recordId")),
|
|
1834
|
+
zoneRecord(a)
|
|
1835
|
+
)
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
async function domainsZoneDelete(ctx, a) {
|
|
1839
|
+
out(await zoneDelete(ctx, a.req("name"), Number(a.req("recordId"))));
|
|
1840
|
+
}
|
|
1597
1841
|
var domainsHandlers = {
|
|
1598
1842
|
"domains get": domainsGet,
|
|
1599
1843
|
"domains set": domainsSet,
|
|
@@ -1604,9 +1848,19 @@ var domainsHandlers = {
|
|
|
1604
1848
|
"domains custom records": customDomainsRecords,
|
|
1605
1849
|
"domains custom status": customDomainsStatus,
|
|
1606
1850
|
"domains custom remove": customDomainsRemove,
|
|
1607
|
-
"domains custom retry": customDomainsRetry
|
|
1851
|
+
"domains custom retry": customDomainsRetry,
|
|
1852
|
+
"domains search": domainsSearch,
|
|
1853
|
+
"domains quote": domainsQuote,
|
|
1854
|
+
"domains buy": domainsBuy,
|
|
1855
|
+
"domains owned": domainsOwned,
|
|
1856
|
+
"domains contact get": domainsContactGet,
|
|
1857
|
+
"domains contact set": domainsContactSet,
|
|
1858
|
+
"domains zone list": domainsZoneList,
|
|
1859
|
+
"domains zone add": domainsZoneAdd,
|
|
1860
|
+
"domains zone update": domainsZoneUpdate,
|
|
1861
|
+
"domains zone delete": domainsZoneDelete
|
|
1608
1862
|
};
|
|
1609
|
-
var domainsHelp = `remy-admin domains \u2014 Manage your app's domains.
|
|
1863
|
+
var domainsHelp = `remy-admin domains \u2014 Manage your app's domains, and buy one.
|
|
1610
1864
|
|
|
1611
1865
|
Platform subdomain (e.g. my-app.madewithremy.com):
|
|
1612
1866
|
get Get current custom subdomain
|
|
@@ -1622,6 +1876,18 @@ Custom domains (customer-owned hostnames, CNAME/A records):
|
|
|
1622
1876
|
custom remove <hostname> Remove a hostname (apex also removes paired www)
|
|
1623
1877
|
custom retry <hostname> Re-trigger validation (after customer fixes DNS)
|
|
1624
1878
|
|
|
1879
|
+
Buying a domain (the workspace owns it; Remy hosts its DNS):
|
|
1880
|
+
search <keyword or name> Names for sale, with price and renewal price
|
|
1881
|
+
quote <name> The definitive price for one name
|
|
1882
|
+
buy <name> --price <dollars> Buy it (not refundable: confirm with the user first)
|
|
1883
|
+
owned The workspace's domains: status, expiry, auto-renew, apps
|
|
1884
|
+
contact get The registrant contact every domain is registered to
|
|
1885
|
+
contact set --first-name ... Set it (needed before the first purchase)
|
|
1886
|
+
zone list <name> The domain's DNS records (ours marked managed)
|
|
1887
|
+
zone add <name> ... Add a record (--type, --answer, --host, --ttl, --priority)
|
|
1888
|
+
zone update <name> <id> ... Replace one of the owner's records
|
|
1889
|
+
zone delete <name> <id> Delete one of the owner's records
|
|
1890
|
+
|
|
1625
1891
|
Usage:
|
|
1626
1892
|
remy-admin domains get
|
|
1627
1893
|
remy-admin domains set my-app
|
|
@@ -1634,14 +1900,44 @@ Usage:
|
|
|
1634
1900
|
remy-admin domains custom status app.acme.com
|
|
1635
1901
|
remy-admin domains custom retry app.acme.com
|
|
1636
1902
|
remy-admin domains custom remove app.acme.com
|
|
1903
|
+
remy-admin domains search acme bakery
|
|
1904
|
+
remy-admin domains quote acmebakery.com
|
|
1905
|
+
remy-admin domains buy acmebakery.com --price 11.99
|
|
1906
|
+
remy-admin domains owned
|
|
1907
|
+
remy-admin domains contact set --first-name Ada --last-name Lovelace --address1 "1 Main St" --city Austin --state TX --zip 78701 --country US --email ada@acme.com --phone +15125550123
|
|
1908
|
+
remy-admin domains zone list acmebakery.com
|
|
1909
|
+
remy-admin domains zone add acmebakery.com --type TXT --host @ --answer "google-site-verification=abc"
|
|
1637
1910
|
|
|
1638
1911
|
Notes:
|
|
1639
1912
|
- 'add' with an apex (e.g. acme.com) auto-creates the www.apex pair and
|
|
1640
1913
|
returns both. 'remove' on an apex also removes its paired www.
|
|
1641
1914
|
- 'list'/'records'/'status' read a CF-synced cache that can be up to ~5
|
|
1642
1915
|
minutes stale. After the customer adds DNS, use 'retry' to force a
|
|
1643
|
-
synchronous re-check.
|
|
1644
|
-
|
|
1916
|
+
synchronous re-check. On a domain bought through Remy there are no records
|
|
1917
|
+
to add, so there's nothing to retry while it waits on the registry.
|
|
1918
|
+
- 'uiStatus' values: waiting_for_dns | issuing_ssl | live | action_needed | reconnecting.
|
|
1919
|
+
- 'buy' charges the workspace the price at once, and it isn't refundable; the
|
|
1920
|
+
domain renews yearly at its renewal price while auto-renew is on (the owner
|
|
1921
|
+
turns it off, renews early or transfers out in Workspace Settings > Domains).
|
|
1922
|
+
Never run 'buy' without the user's explicit confirmation of the name, the
|
|
1923
|
+
price and the renewal price. --price is the quote's; if the price has moved,
|
|
1924
|
+
'buy' is refused with price_changed and the new price, to confirm again.
|
|
1925
|
+
- The first purchase needs the registrant contact ('contact set'): the
|
|
1926
|
+
domain's legal owner. ICANN emails that address to verify it within 15
|
|
1927
|
+
days, or the domain stops resolving; tell the user to watch for it.
|
|
1928
|
+
- Other refusals: registrant_contact_required, insufficient_credits/*,
|
|
1929
|
+
entitlement_required:registered_domains (the plan holds no more domains:
|
|
1930
|
+
a paid plan holds 20), domain_registration_rate (3 in any 30 days),
|
|
1931
|
+
domain_unavailable, tld_not_supported,
|
|
1932
|
+
trademark_claim, registrar_busy (try again), registrar_payment (temporarily
|
|
1933
|
+
unavailable), namecom_not_configured (this deployment doesn't sell domains).
|
|
1934
|
+
- A bought domain is usually active when 'buy' returns; 'owned' shows a
|
|
1935
|
+
pending one settle. It connects to nothing by itself: 'custom add',
|
|
1936
|
+
'email domains add' and 'email inbound-domains add' on it write their DNS
|
|
1937
|
+
records automatically (the response's registeredDomain says what was
|
|
1938
|
+
written), so there's nothing to hand the user.
|
|
1939
|
+
- Records the platform wrote for a connection are 'managed' in 'zone list' and
|
|
1940
|
+
can't be changed; they go when the connection is removed.`;
|
|
1645
1941
|
|
|
1646
1942
|
// src/ops/users.ts
|
|
1647
1943
|
function list4(ctx, params = {}) {
|
|
@@ -3375,7 +3671,7 @@ async function allDocuments(ctx, params) {
|
|
|
3375
3671
|
function list8(ctx) {
|
|
3376
3672
|
return call(ctx, "GET", base(ctx.appId));
|
|
3377
3673
|
}
|
|
3378
|
-
function
|
|
3674
|
+
function search2(ctx, params) {
|
|
3379
3675
|
const {
|
|
3380
3676
|
slug,
|
|
3381
3677
|
query: query3,
|
|
@@ -6211,7 +6507,7 @@ async function dataSourcesSearch(ctx, a) {
|
|
|
6211
6507
|
const filter = filterFromFlags(a);
|
|
6212
6508
|
const maxPerDocument = a.num("max-per-document");
|
|
6213
6509
|
out(
|
|
6214
|
-
await
|
|
6510
|
+
await search2(ctx, {
|
|
6215
6511
|
slug: sourceOf(a),
|
|
6216
6512
|
query: a.req("query"),
|
|
6217
6513
|
...topK ? { topK } : {},
|
|
@@ -8619,11 +8915,11 @@ function logs(ctx, params) {
|
|
|
8619
8915
|
if (params.limit) {
|
|
8620
8916
|
query3.set("limit", String(params.limit));
|
|
8621
8917
|
}
|
|
8622
|
-
const
|
|
8918
|
+
const search3 = query3.toString();
|
|
8623
8919
|
return call(
|
|
8624
8920
|
ctx,
|
|
8625
8921
|
"GET",
|
|
8626
|
-
`${base7(ctx.appId)}/${encodeURIComponent(params.id)}/logs${
|
|
8922
|
+
`${base7(ctx.appId)}/${encodeURIComponent(params.id)}/logs${search3 ? `?${search3}` : ""}`
|
|
8627
8923
|
);
|
|
8628
8924
|
}
|
|
8629
8925
|
function provision(ctx, params) {
|
|
@@ -9371,7 +9667,7 @@ Commands:
|
|
|
9371
9667
|
analytics View traffic, top-N, geo, and AI-referral insights
|
|
9372
9668
|
releases View and monitor releases
|
|
9373
9669
|
diagnostics View the post-deploy Lighthouse audit (scores, issues, raw report)
|
|
9374
|
-
domains
|
|
9670
|
+
domains Subdomain, custom domains, and buying a domain
|
|
9375
9671
|
users Manage app users and roles
|
|
9376
9672
|
db Query the production database
|
|
9377
9673
|
secrets Manage app secrets (env vars)
|