@getcirrus/pds 0.3.0 → 0.4.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/dist/cli.js +594 -75
- package/dist/index.js +17 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11,6 +11,8 @@ import { resolve } from "node:path";
|
|
|
11
11
|
import { CompositeDidDocumentResolver, DohJsonHandleResolver, PlcDidDocumentResolver, WebDidDocumentResolver } from "@atcute/identity-resolver";
|
|
12
12
|
import pc from "picocolors";
|
|
13
13
|
import { Client, ClientResponseError, ok } from "@atcute/client";
|
|
14
|
+
import "@atcute/bluesky";
|
|
15
|
+
import "@atcute/atproto";
|
|
14
16
|
import { getPdsEndpoint } from "@atcute/identity";
|
|
15
17
|
|
|
16
18
|
//#region src/cli/utils/wrangler.ts
|
|
@@ -955,7 +957,7 @@ function createAuthHandler(baseUrl, token) {
|
|
|
955
957
|
});
|
|
956
958
|
};
|
|
957
959
|
}
|
|
958
|
-
var PDSClient = class {
|
|
960
|
+
var PDSClient = class PDSClient {
|
|
959
961
|
client;
|
|
960
962
|
authToken;
|
|
961
963
|
constructor(baseUrl, authToken) {
|
|
@@ -1201,6 +1203,23 @@ var PDSClient = class {
|
|
|
1201
1203
|
}));
|
|
1202
1204
|
}
|
|
1203
1205
|
/**
|
|
1206
|
+
* Emit identity event to notify relays to refresh handle verification
|
|
1207
|
+
*/
|
|
1208
|
+
async emitIdentity() {
|
|
1209
|
+
const url = new URL("/xrpc/gg.mk.experimental.emitIdentityEvent", this.baseUrl);
|
|
1210
|
+
const headers = {};
|
|
1211
|
+
if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
|
|
1212
|
+
const res = await fetch(url.toString(), {
|
|
1213
|
+
method: "POST",
|
|
1214
|
+
headers
|
|
1215
|
+
});
|
|
1216
|
+
if (!res.ok) {
|
|
1217
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
1218
|
+
throw new Error(errorBody.message ?? `Request failed: ${res.status}`);
|
|
1219
|
+
}
|
|
1220
|
+
return res.json();
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1204
1223
|
* Check if the PDS is reachable
|
|
1205
1224
|
*/
|
|
1206
1225
|
async healthCheck() {
|
|
@@ -1313,8 +1332,78 @@ var PDSClient = class {
|
|
|
1313
1332
|
}
|
|
1314
1333
|
}
|
|
1315
1334
|
/**
|
|
1335
|
+
* Get a record from the repository
|
|
1336
|
+
*/
|
|
1337
|
+
async getRecord(repo, collection, rkey) {
|
|
1338
|
+
try {
|
|
1339
|
+
return await ok(this.client.get("com.atproto.repo.getRecord", { params: {
|
|
1340
|
+
repo,
|
|
1341
|
+
collection,
|
|
1342
|
+
rkey
|
|
1343
|
+
} }));
|
|
1344
|
+
} catch (err) {
|
|
1345
|
+
if (err instanceof ClientResponseError && err.status === 404) return null;
|
|
1346
|
+
throw err;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Create or update a record in the repository
|
|
1351
|
+
*/
|
|
1352
|
+
async putRecord(repo, collection, rkey, record) {
|
|
1353
|
+
return ok(this.client.post("com.atproto.repo.putRecord", { input: {
|
|
1354
|
+
repo,
|
|
1355
|
+
collection,
|
|
1356
|
+
rkey,
|
|
1357
|
+
record
|
|
1358
|
+
} }));
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Get the user's profile record
|
|
1362
|
+
*/
|
|
1363
|
+
async getProfile(did) {
|
|
1364
|
+
const record = await this.getRecord(did, "app.bsky.actor.profile", "self");
|
|
1365
|
+
if (!record) return null;
|
|
1366
|
+
return record.value;
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Create or update the user's profile
|
|
1370
|
+
*/
|
|
1371
|
+
async putProfile(did, profile) {
|
|
1372
|
+
return this.putRecord(did, "app.bsky.actor.profile", "self", {
|
|
1373
|
+
$type: "app.bsky.actor.profile",
|
|
1374
|
+
...profile
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
static RELAY_URLS = ["https://relay1.us-west.bsky.network", "https://relay1.us-east.bsky.network"];
|
|
1378
|
+
/**
|
|
1379
|
+
* Get relay's view of this PDS host status from a single relay.
|
|
1380
|
+
* Calls com.atproto.sync.getHostStatus on the relay.
|
|
1381
|
+
*/
|
|
1382
|
+
async getRelayHostStatus(pdsHostname, relayUrl) {
|
|
1383
|
+
try {
|
|
1384
|
+
const url = new URL("/xrpc/com.atproto.sync.getHostStatus", relayUrl);
|
|
1385
|
+
url.searchParams.set("hostname", pdsHostname);
|
|
1386
|
+
const res = await fetch(url.toString());
|
|
1387
|
+
if (!res.ok) return null;
|
|
1388
|
+
return {
|
|
1389
|
+
...await res.json(),
|
|
1390
|
+
relay: relayUrl
|
|
1391
|
+
};
|
|
1392
|
+
} catch {
|
|
1393
|
+
return null;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Get relay status from all known relays.
|
|
1398
|
+
* Returns results from each relay that responds.
|
|
1399
|
+
*/
|
|
1400
|
+
async getAllRelayHostStatus(pdsHostname) {
|
|
1401
|
+
return (await Promise.all(PDSClient.RELAY_URLS.map((url) => this.getRelayHostStatus(pdsHostname, url)))).filter((r) => r !== null);
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1316
1404
|
* Request the relay to crawl this PDS.
|
|
1317
1405
|
* This notifies the Bluesky relay that the PDS is active and ready for federation.
|
|
1406
|
+
* Uses bsky.network by default (the main relay endpoint).
|
|
1318
1407
|
*/
|
|
1319
1408
|
async requestCrawl(pdsHostname, relayUrl = "https://bsky.network") {
|
|
1320
1409
|
try {
|
|
@@ -1672,24 +1761,261 @@ function showNextSteps(pm, sourceDomain) {
|
|
|
1672
1761
|
]), "Almost there!");
|
|
1673
1762
|
}
|
|
1674
1763
|
|
|
1764
|
+
//#endregion
|
|
1765
|
+
//#region src/cli/utils/checks.ts
|
|
1766
|
+
/**
|
|
1767
|
+
* Check that handle resolves to the expected DID
|
|
1768
|
+
*/
|
|
1769
|
+
async function checkHandleResolution(handle, expectedDid) {
|
|
1770
|
+
const resolvedDid = await resolveHandleToDid(handle);
|
|
1771
|
+
if (!resolvedDid) return {
|
|
1772
|
+
ok: false,
|
|
1773
|
+
message: `@${handle} does not resolve to any DID`,
|
|
1774
|
+
detail: "Update your DNS TXT record or .well-known/atproto-did file"
|
|
1775
|
+
};
|
|
1776
|
+
if (resolvedDid !== expectedDid) return {
|
|
1777
|
+
ok: false,
|
|
1778
|
+
message: `@${handle} resolves to wrong DID`,
|
|
1779
|
+
detail: `Expected: ${expectedDid}\n Got: ${resolvedDid}`
|
|
1780
|
+
};
|
|
1781
|
+
return {
|
|
1782
|
+
ok: true,
|
|
1783
|
+
message: `@${handle} → ${expectedDid.slice(0, 24)}...`
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Check that handle resolves via DNS and/or HTTP, returning both methods
|
|
1788
|
+
*/
|
|
1789
|
+
async function checkHandleResolutionDetailed(client, handle, expectedDid) {
|
|
1790
|
+
const [httpDid, dnsDid] = await Promise.all([client.checkHandleViaHttp(handle), client.checkHandleViaDns(handle)]);
|
|
1791
|
+
const httpValid = httpDid === expectedDid;
|
|
1792
|
+
const dnsValid = dnsDid === expectedDid;
|
|
1793
|
+
const methods = [];
|
|
1794
|
+
if (dnsValid) methods.push("DNS");
|
|
1795
|
+
if (httpValid) methods.push("HTTP");
|
|
1796
|
+
return {
|
|
1797
|
+
ok: httpValid || dnsValid,
|
|
1798
|
+
httpDid,
|
|
1799
|
+
dnsDid,
|
|
1800
|
+
methods
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
/**
|
|
1804
|
+
* Check that DID document points to the expected PDS endpoint
|
|
1805
|
+
*/
|
|
1806
|
+
async function checkDidDocument(did, expectedPdsUrl) {
|
|
1807
|
+
const didDoc = await new DidResolver().resolve(did);
|
|
1808
|
+
const expectedEndpoint = expectedPdsUrl.replace(/\/$/, "");
|
|
1809
|
+
if (!didDoc) return {
|
|
1810
|
+
ok: false,
|
|
1811
|
+
message: `Could not resolve DID document for ${did}`,
|
|
1812
|
+
detail: "Make sure your DID is published to the PLC directory or did:web endpoint"
|
|
1813
|
+
};
|
|
1814
|
+
const pdsService = didDoc.service?.find((s) => {
|
|
1815
|
+
return (Array.isArray(s.type) ? s.type : [s.type]).includes("AtprotoPersonalDataServer") || s.id === "#atproto_pds";
|
|
1816
|
+
});
|
|
1817
|
+
if (!pdsService?.serviceEndpoint) return {
|
|
1818
|
+
ok: false,
|
|
1819
|
+
message: "DID document has no PDS service endpoint",
|
|
1820
|
+
detail: "Update your DID document to include an AtprotoPersonalDataServer service"
|
|
1821
|
+
};
|
|
1822
|
+
const actualEndpoint = pdsService.serviceEndpoint.replace(/\/$/, "");
|
|
1823
|
+
if (actualEndpoint !== expectedEndpoint) return {
|
|
1824
|
+
ok: false,
|
|
1825
|
+
message: "DID document points to different PDS",
|
|
1826
|
+
detail: `Expected: ${expectedEndpoint}\n Got: ${actualEndpoint}`
|
|
1827
|
+
};
|
|
1828
|
+
return {
|
|
1829
|
+
ok: true,
|
|
1830
|
+
message: `PDS endpoint → ${expectedEndpoint}`
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Check that DID resolves and returns the PDS endpoint (simpler version using PDSClient)
|
|
1835
|
+
*/
|
|
1836
|
+
async function checkDidResolution(client, did, expectedPdsHostname) {
|
|
1837
|
+
const resolved = await client.resolveDid(did);
|
|
1838
|
+
const resolveMethod = did.startsWith("did:plc:") ? "plc.directory" : did.startsWith("did:web:") ? "/.well-known/did.json" : "unknown";
|
|
1839
|
+
if (!resolved.pdsEndpoint) return {
|
|
1840
|
+
ok: false,
|
|
1841
|
+
pdsEndpoint: null,
|
|
1842
|
+
resolveMethod
|
|
1843
|
+
};
|
|
1844
|
+
const expectedEndpoint = `https://${expectedPdsHostname}`;
|
|
1845
|
+
return {
|
|
1846
|
+
ok: resolved.pdsEndpoint === expectedEndpoint || resolved.pdsEndpoint === expectedPdsHostname,
|
|
1847
|
+
pdsEndpoint: resolved.pdsEndpoint,
|
|
1848
|
+
resolveMethod
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Check that all blobs are imported
|
|
1853
|
+
*/
|
|
1854
|
+
function checkBlobsImported(status) {
|
|
1855
|
+
const missingBlobs = status.expectedBlobs - status.importedBlobs;
|
|
1856
|
+
if (missingBlobs > 0) return {
|
|
1857
|
+
ok: false,
|
|
1858
|
+
message: `${missingBlobs} blob${missingBlobs === 1 ? "" : "s"} missing`,
|
|
1859
|
+
detail: "Run 'pds migrate' to import missing blobs before activating"
|
|
1860
|
+
};
|
|
1861
|
+
return {
|
|
1862
|
+
ok: true,
|
|
1863
|
+
message: `${status.importedBlobs}/${status.expectedBlobs} blobs imported`
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
/**
|
|
1867
|
+
* Check that repository data exists and is properly initialised
|
|
1868
|
+
*/
|
|
1869
|
+
function checkRepoInitialised(status) {
|
|
1870
|
+
if (!status.repoCommit) return {
|
|
1871
|
+
ok: false,
|
|
1872
|
+
message: "No repo data imported",
|
|
1873
|
+
detail: "Run 'pds migrate' to import your repository first"
|
|
1874
|
+
};
|
|
1875
|
+
if (status.indexedRecords === 0) return {
|
|
1876
|
+
ok: false,
|
|
1877
|
+
message: "Repository has no indexed records",
|
|
1878
|
+
detail: "Run 'pds migrate' to import your repository"
|
|
1879
|
+
};
|
|
1880
|
+
return {
|
|
1881
|
+
ok: true,
|
|
1882
|
+
message: `${status.repoBlocks.toLocaleString()} blocks, ${status.indexedRecords.toLocaleString()} records`
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* Check that repo is complete for activation (combines blob and repo checks)
|
|
1887
|
+
*/
|
|
1888
|
+
function checkRepoComplete(status) {
|
|
1889
|
+
const repoCheck = checkRepoInitialised(status);
|
|
1890
|
+
if (!repoCheck.ok) return repoCheck;
|
|
1891
|
+
if (status.expectedBlobs > 0) {
|
|
1892
|
+
const blobCheck = checkBlobsImported(status);
|
|
1893
|
+
if (!blobCheck.ok) return blobCheck;
|
|
1894
|
+
}
|
|
1895
|
+
return {
|
|
1896
|
+
ok: true,
|
|
1897
|
+
message: `${status.repoBlocks} blocks, ${status.importedBlobs} blobs`
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Check if profile is indexed by AppView
|
|
1902
|
+
*/
|
|
1903
|
+
async function checkAppViewIndexing(client, did) {
|
|
1904
|
+
if (!await client.checkAppViewIndexing(did)) return {
|
|
1905
|
+
ok: false,
|
|
1906
|
+
message: "Profile not found on AppView",
|
|
1907
|
+
detail: "This may be normal for new accounts"
|
|
1908
|
+
};
|
|
1909
|
+
return {
|
|
1910
|
+
ok: true,
|
|
1911
|
+
message: "Profile indexed by AppView"
|
|
1912
|
+
};
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1675
1915
|
//#endregion
|
|
1676
1916
|
//#region src/cli/commands/activate.ts
|
|
1677
1917
|
/**
|
|
1678
1918
|
* Activate account command - enables writes after migration
|
|
1679
1919
|
*/
|
|
1920
|
+
/**
|
|
1921
|
+
* Run pre-activation checks
|
|
1922
|
+
*/
|
|
1923
|
+
async function runChecks(handle, did, pdsUrl, status) {
|
|
1924
|
+
const checks = [];
|
|
1925
|
+
p.log.step("Checking handle resolution...");
|
|
1926
|
+
const handleResult = await checkHandleResolution(handle, did);
|
|
1927
|
+
checks.push({
|
|
1928
|
+
name: "Handle",
|
|
1929
|
+
...handleResult
|
|
1930
|
+
});
|
|
1931
|
+
p.log.step("Checking DID document...");
|
|
1932
|
+
const didResult = await checkDidDocument(did, pdsUrl);
|
|
1933
|
+
checks.push({
|
|
1934
|
+
name: "DID",
|
|
1935
|
+
...didResult
|
|
1936
|
+
});
|
|
1937
|
+
p.log.step("Checking repo status...");
|
|
1938
|
+
const repoResult = checkRepoComplete(status);
|
|
1939
|
+
checks.push({
|
|
1940
|
+
name: "Repo",
|
|
1941
|
+
...repoResult
|
|
1942
|
+
});
|
|
1943
|
+
return checks;
|
|
1944
|
+
}
|
|
1945
|
+
function logCheck(check) {
|
|
1946
|
+
const icon = check.ok ? pc.green("✓") : pc.red("✗");
|
|
1947
|
+
const name = pc.bold(check.name.padEnd(8));
|
|
1948
|
+
console.log(` ${icon} ${name} ${check.message}`);
|
|
1949
|
+
if (check.detail && !check.ok) for (const line of check.detail.split("\n")) console.log(` ${pc.dim(line)}`);
|
|
1950
|
+
}
|
|
1951
|
+
/**
|
|
1952
|
+
* Prompt user to create a profile if one doesn't exist
|
|
1953
|
+
*/
|
|
1954
|
+
async function promptCreateProfile(client, did, handle) {
|
|
1955
|
+
const spinner = p.spinner();
|
|
1956
|
+
spinner.start("Checking profile...");
|
|
1957
|
+
const existingProfile = await client.getProfile(did);
|
|
1958
|
+
spinner.stop(existingProfile ? "Profile found" : "No profile found");
|
|
1959
|
+
if (!existingProfile) {
|
|
1960
|
+
const createProfile = await p.confirm({
|
|
1961
|
+
message: "Create a profile? (recommended for visibility on the network)",
|
|
1962
|
+
initialValue: true
|
|
1963
|
+
});
|
|
1964
|
+
if (p.isCancel(createProfile)) {
|
|
1965
|
+
p.cancel("Cancelled.");
|
|
1966
|
+
process.exit(0);
|
|
1967
|
+
}
|
|
1968
|
+
if (createProfile) {
|
|
1969
|
+
const displayName = await promptText({
|
|
1970
|
+
message: "Display name:",
|
|
1971
|
+
placeholder: handle || "Your Name",
|
|
1972
|
+
validate: (v) => {
|
|
1973
|
+
if (v && v.length > 64) return "Display name must be 64 characters or less";
|
|
1974
|
+
}
|
|
1975
|
+
});
|
|
1976
|
+
const description = await promptText({
|
|
1977
|
+
message: "Bio (optional):",
|
|
1978
|
+
placeholder: "Tell us about yourself",
|
|
1979
|
+
validate: (v) => {
|
|
1980
|
+
if (v && v.length > 256) return "Bio must be 256 characters or less";
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
spinner.start("Creating profile...");
|
|
1984
|
+
try {
|
|
1985
|
+
await client.putProfile(did, {
|
|
1986
|
+
displayName: displayName || void 0,
|
|
1987
|
+
description: description || void 0
|
|
1988
|
+
});
|
|
1989
|
+
spinner.stop("Profile created!");
|
|
1990
|
+
} catch (err) {
|
|
1991
|
+
spinner.stop("Failed to create profile");
|
|
1992
|
+
p.log.warn(err instanceof Error ? err.message : "Could not create profile");
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1680
1997
|
const activateCommand = defineCommand({
|
|
1681
1998
|
meta: {
|
|
1682
1999
|
name: "activate",
|
|
1683
2000
|
description: "Activate your account to enable writes and go live"
|
|
1684
2001
|
},
|
|
1685
|
-
args: {
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
2002
|
+
args: {
|
|
2003
|
+
dev: {
|
|
2004
|
+
type: "boolean",
|
|
2005
|
+
description: "Target local development server instead of production",
|
|
2006
|
+
default: false
|
|
2007
|
+
},
|
|
2008
|
+
yes: {
|
|
2009
|
+
type: "boolean",
|
|
2010
|
+
alias: "y",
|
|
2011
|
+
description: "Skip confirmation prompts",
|
|
2012
|
+
default: false
|
|
2013
|
+
}
|
|
2014
|
+
},
|
|
1690
2015
|
async run({ args }) {
|
|
1691
2016
|
const pm = detectPackageManager();
|
|
1692
2017
|
const isDev = args.dev;
|
|
2018
|
+
const skipConfirm = args.yes;
|
|
1693
2019
|
p.intro("🦋 Activate Account");
|
|
1694
2020
|
const vars = getVars();
|
|
1695
2021
|
let targetUrl;
|
|
@@ -1708,11 +2034,17 @@ const activateCommand = defineCommand({
|
|
|
1708
2034
|
};
|
|
1709
2035
|
const authToken = config.AUTH_TOKEN;
|
|
1710
2036
|
const handle = config.HANDLE;
|
|
2037
|
+
const did = config.DID;
|
|
1711
2038
|
if (!authToken) {
|
|
1712
2039
|
p.log.error("No AUTH_TOKEN found. Run 'pds init' first.");
|
|
1713
2040
|
p.outro("Activation cancelled.");
|
|
1714
2041
|
process.exit(1);
|
|
1715
2042
|
}
|
|
2043
|
+
if (!handle || !did) {
|
|
2044
|
+
p.log.error("No HANDLE or DID found. Run 'pds init' first.");
|
|
2045
|
+
p.outro("Activation cancelled.");
|
|
2046
|
+
process.exit(1);
|
|
2047
|
+
}
|
|
1716
2048
|
const client = new PDSClient(targetUrl, authToken);
|
|
1717
2049
|
const spinner = p.spinner();
|
|
1718
2050
|
spinner.start(`Checking PDS at ${targetDomain}...`);
|
|
@@ -1729,6 +2061,7 @@ const activateCommand = defineCommand({
|
|
|
1729
2061
|
spinner.stop("Account status retrieved");
|
|
1730
2062
|
if (status.active) {
|
|
1731
2063
|
p.log.info("Your account is already active.");
|
|
2064
|
+
await promptCreateProfile(client, did, handle);
|
|
1732
2065
|
const pdsHostname$1 = config.PDS_HOSTNAME;
|
|
1733
2066
|
if (pdsHostname$1 && !isDev) {
|
|
1734
2067
|
const pingRelay = await p.confirm({
|
|
@@ -1740,29 +2073,44 @@ const activateCommand = defineCommand({
|
|
|
1740
2073
|
process.exit(0);
|
|
1741
2074
|
}
|
|
1742
2075
|
if (pingRelay) {
|
|
1743
|
-
spinner.start("
|
|
1744
|
-
if (await client.requestCrawl(pdsHostname$1)) spinner.stop("
|
|
1745
|
-
else spinner.stop("Could not
|
|
2076
|
+
spinner.start("Requesting crawl from relay...");
|
|
2077
|
+
if (await client.requestCrawl(pdsHostname$1)) spinner.stop("Crawl requested");
|
|
2078
|
+
else spinner.stop("Could not request crawl");
|
|
1746
2079
|
}
|
|
1747
2080
|
}
|
|
1748
2081
|
p.outro("All good!");
|
|
1749
2082
|
return;
|
|
1750
2083
|
}
|
|
1751
|
-
p.
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
2084
|
+
p.log.info("");
|
|
2085
|
+
p.log.info(pc.bold("Pre-activation checks:"));
|
|
2086
|
+
const checks = await runChecks(handle, did, targetUrl, status);
|
|
2087
|
+
console.log("");
|
|
2088
|
+
for (const check of checks) logCheck(check);
|
|
2089
|
+
console.log("");
|
|
2090
|
+
const hasFailures = checks.some((c) => !c.ok);
|
|
2091
|
+
if (hasFailures) {
|
|
2092
|
+
p.log.warn(pc.yellow("Some checks failed. Activating now may cause issues."));
|
|
2093
|
+
p.log.info("");
|
|
2094
|
+
if (skipConfirm) p.log.info("Proceeding anyway (--yes flag)");
|
|
2095
|
+
else {
|
|
2096
|
+
const proceed = await p.confirm({
|
|
2097
|
+
message: "Proceed with activation anyway?",
|
|
2098
|
+
initialValue: false
|
|
2099
|
+
});
|
|
2100
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
2101
|
+
p.cancel("Activation cancelled. Fix the issues above and try again.");
|
|
2102
|
+
process.exit(0);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
} else if (!skipConfirm) {
|
|
2106
|
+
const confirm = await p.confirm({
|
|
2107
|
+
message: "Activate account?",
|
|
2108
|
+
initialValue: true
|
|
2109
|
+
});
|
|
2110
|
+
if (p.isCancel(confirm) || !confirm) {
|
|
2111
|
+
p.cancel("Activation cancelled.");
|
|
2112
|
+
process.exit(0);
|
|
2113
|
+
}
|
|
1766
2114
|
}
|
|
1767
2115
|
spinner.start("Activating account...");
|
|
1768
2116
|
try {
|
|
@@ -1774,17 +2122,54 @@ const activateCommand = defineCommand({
|
|
|
1774
2122
|
p.outro("Activation failed.");
|
|
1775
2123
|
process.exit(1);
|
|
1776
2124
|
}
|
|
2125
|
+
await promptCreateProfile(client, did, handle);
|
|
2126
|
+
spinner.start("Verifying activation...");
|
|
2127
|
+
if (!(await client.getAccountStatus()).active) {
|
|
2128
|
+
spinner.stop("Verification failed");
|
|
2129
|
+
p.log.error("Account was activated but is not showing as active.");
|
|
2130
|
+
p.log.info("Try running 'pds status' to check the current state.");
|
|
2131
|
+
p.outro("Activation may have failed.");
|
|
2132
|
+
process.exit(1);
|
|
2133
|
+
}
|
|
2134
|
+
spinner.stop("Account is active");
|
|
1777
2135
|
const pdsHostname = config.PDS_HOSTNAME;
|
|
1778
2136
|
if (pdsHostname && !isDev) {
|
|
1779
|
-
spinner.start("
|
|
1780
|
-
if (await client.requestCrawl(pdsHostname)) spinner.stop("
|
|
2137
|
+
spinner.start("Requesting crawl from relay...");
|
|
2138
|
+
if (await client.requestCrawl(pdsHostname)) spinner.stop("Crawl requested");
|
|
1781
2139
|
else {
|
|
1782
|
-
spinner.stop("Could not
|
|
1783
|
-
p.log.warn("Run 'pds activate' again later to retry
|
|
2140
|
+
spinner.stop("Could not request crawl");
|
|
2141
|
+
p.log.warn("Run 'pds activate' again later to retry requesting a crawl.");
|
|
1784
2142
|
}
|
|
1785
2143
|
}
|
|
1786
2144
|
p.log.success("Welcome to the Atmosphere! 🦋");
|
|
1787
2145
|
p.log.info("Your account is now live and accepting writes.");
|
|
2146
|
+
if (!hasFailures) {
|
|
2147
|
+
p.log.info("");
|
|
2148
|
+
let shouldEmit = skipConfirm;
|
|
2149
|
+
if (!skipConfirm) {
|
|
2150
|
+
const emitConfirm = await p.confirm({
|
|
2151
|
+
message: "Emit identity event to notify relays?",
|
|
2152
|
+
initialValue: true
|
|
2153
|
+
});
|
|
2154
|
+
shouldEmit = !p.isCancel(emitConfirm) && emitConfirm;
|
|
2155
|
+
}
|
|
2156
|
+
if (shouldEmit) {
|
|
2157
|
+
spinner.start("Emitting identity event...");
|
|
2158
|
+
try {
|
|
2159
|
+
const result = await client.emitIdentity();
|
|
2160
|
+
spinner.stop(`Identity event emitted (seq: ${result.seq})`);
|
|
2161
|
+
} catch (err) {
|
|
2162
|
+
spinner.stop("Failed to emit identity event");
|
|
2163
|
+
p.log.warn(err instanceof Error ? err.message : "Could not emit identity");
|
|
2164
|
+
p.log.info("You can try again later with: pds emit-identity");
|
|
2165
|
+
}
|
|
2166
|
+
} else p.log.info("To notify relays later, run: pds emit-identity");
|
|
2167
|
+
} else {
|
|
2168
|
+
p.log.info("");
|
|
2169
|
+
p.log.info("Some checks failed, so identity was not emitted automatically.");
|
|
2170
|
+
p.log.info("Once your handle and DID are configured correctly, run:");
|
|
2171
|
+
p.log.info(" pds emit-identity");
|
|
2172
|
+
}
|
|
1788
2173
|
p.outro("All set!");
|
|
1789
2174
|
}
|
|
1790
2175
|
});
|
|
@@ -1796,19 +2181,47 @@ const activateCommand = defineCommand({
|
|
|
1796
2181
|
*/
|
|
1797
2182
|
const brightNote = (lines) => lines.map((l) => `\x1b[0m${l}`).join("\n");
|
|
1798
2183
|
const bold = (text) => pc.bold(text);
|
|
2184
|
+
/**
|
|
2185
|
+
* Run identity verification checks - for deactivate, we just inform the user
|
|
2186
|
+
*/
|
|
2187
|
+
async function runIdentityChecks(handle, did, pdsUrl) {
|
|
2188
|
+
const checks = [];
|
|
2189
|
+
p.log.step("Checking handle resolution...");
|
|
2190
|
+
const handleResult = await checkHandleResolution(handle, did);
|
|
2191
|
+
checks.push({
|
|
2192
|
+
name: "Handle resolution",
|
|
2193
|
+
...handleResult
|
|
2194
|
+
});
|
|
2195
|
+
p.log.step("Checking DID document...");
|
|
2196
|
+
const didResult = await checkDidDocument(did, pdsUrl);
|
|
2197
|
+
checks.push({
|
|
2198
|
+
name: "DID document",
|
|
2199
|
+
...didResult
|
|
2200
|
+
});
|
|
2201
|
+
return checks;
|
|
2202
|
+
}
|
|
1799
2203
|
const deactivateCommand = defineCommand({
|
|
1800
2204
|
meta: {
|
|
1801
2205
|
name: "deactivate",
|
|
1802
2206
|
description: "Deactivate your account to enable re-import"
|
|
1803
2207
|
},
|
|
1804
|
-
args: {
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
2208
|
+
args: {
|
|
2209
|
+
dev: {
|
|
2210
|
+
type: "boolean",
|
|
2211
|
+
description: "Target local development server instead of production",
|
|
2212
|
+
default: false
|
|
2213
|
+
},
|
|
2214
|
+
yes: {
|
|
2215
|
+
type: "boolean",
|
|
2216
|
+
alias: "y",
|
|
2217
|
+
description: "Skip confirmation prompts",
|
|
2218
|
+
default: false
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
1809
2221
|
async run({ args }) {
|
|
1810
2222
|
const pm = detectPackageManager();
|
|
1811
2223
|
const isDev = args.dev;
|
|
2224
|
+
const skipConfirm = args.yes;
|
|
1812
2225
|
p.intro("🦋 Deactivate Account");
|
|
1813
2226
|
const vars = getVars();
|
|
1814
2227
|
let targetUrl;
|
|
@@ -1827,11 +2240,17 @@ const deactivateCommand = defineCommand({
|
|
|
1827
2240
|
};
|
|
1828
2241
|
const authToken = config.AUTH_TOKEN;
|
|
1829
2242
|
const handle = config.HANDLE;
|
|
2243
|
+
const did = config.DID;
|
|
1830
2244
|
if (!authToken) {
|
|
1831
2245
|
p.log.error("No AUTH_TOKEN found. Run 'pds init' first.");
|
|
1832
2246
|
p.outro("Deactivation cancelled.");
|
|
1833
2247
|
process.exit(1);
|
|
1834
2248
|
}
|
|
2249
|
+
if (!handle || !did) {
|
|
2250
|
+
p.log.error("No HANDLE or DID found. Run 'pds init' first.");
|
|
2251
|
+
p.outro("Deactivation cancelled.");
|
|
2252
|
+
process.exit(1);
|
|
2253
|
+
}
|
|
1835
2254
|
const client = new PDSClient(targetUrl, authToken);
|
|
1836
2255
|
const spinner = p.spinner();
|
|
1837
2256
|
spinner.start(`Checking PDS at ${targetDomain}...`);
|
|
@@ -1852,8 +2271,17 @@ const deactivateCommand = defineCommand({
|
|
|
1852
2271
|
p.outro("Already deactivated.");
|
|
1853
2272
|
return;
|
|
1854
2273
|
}
|
|
2274
|
+
p.log.info("");
|
|
2275
|
+
p.log.info(pc.bold("Current identity status:"));
|
|
2276
|
+
const checks = await runIdentityChecks(handle, did, targetUrl);
|
|
2277
|
+
for (const check of checks) if (check.ok) p.log.success(`${check.name}: ${check.message}`);
|
|
2278
|
+
else {
|
|
2279
|
+
p.log.warn(`${check.name}: ${check.message}`);
|
|
2280
|
+
if (check.detail) p.log.info(` ${check.detail}`);
|
|
2281
|
+
}
|
|
2282
|
+
p.log.info("");
|
|
1855
2283
|
p.note(brightNote([
|
|
1856
|
-
bold(`⚠️ WARNING: This will disable writes for @${handle
|
|
2284
|
+
bold(`⚠️ WARNING: This will disable writes for @${handle}`),
|
|
1857
2285
|
"",
|
|
1858
2286
|
"Your account will:",
|
|
1859
2287
|
" • Stop accepting new posts, follows, and other writes",
|
|
@@ -1862,13 +2290,15 @@ const deactivateCommand = defineCommand({
|
|
|
1862
2290
|
"",
|
|
1863
2291
|
bold("Only deactivate if you need to re-import your data.")
|
|
1864
2292
|
]), "Deactivate Account");
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
p.
|
|
1871
|
-
|
|
2293
|
+
if (!skipConfirm) {
|
|
2294
|
+
const confirm = await p.confirm({
|
|
2295
|
+
message: "Are you sure you want to deactivate?",
|
|
2296
|
+
initialValue: false
|
|
2297
|
+
});
|
|
2298
|
+
if (p.isCancel(confirm) || !confirm) {
|
|
2299
|
+
p.cancel("Deactivation cancelled.");
|
|
2300
|
+
process.exit(0);
|
|
2301
|
+
}
|
|
1872
2302
|
}
|
|
1873
2303
|
spinner.start("Deactivating account...");
|
|
1874
2304
|
try {
|
|
@@ -1965,14 +2395,15 @@ const statusCommand = defineCommand({
|
|
|
1965
2395
|
}
|
|
1966
2396
|
console.log();
|
|
1967
2397
|
console.log(pc.bold("Repository"));
|
|
1968
|
-
|
|
2398
|
+
const repoCheck = checkRepoInitialised(status);
|
|
2399
|
+
if (repoCheck.ok) {
|
|
1969
2400
|
const shortCid = status.repoCommit.slice(0, 12) + "..." + status.repoCommit.slice(-4);
|
|
1970
2401
|
const shortRev = status.repoRev ? status.repoRev.slice(0, 8) + "..." : "none";
|
|
1971
2402
|
console.log(` ${CHECK} Initialized: ${pc.dim(shortCid)} (rev: ${shortRev})`);
|
|
1972
|
-
console.log(` ${INFO} ${
|
|
2403
|
+
console.log(` ${INFO} ${repoCheck.message}`);
|
|
1973
2404
|
} else {
|
|
1974
|
-
console.log(` ${WARN}
|
|
1975
|
-
console.log(pc.dim(
|
|
2405
|
+
console.log(` ${WARN} ${repoCheck.message}`);
|
|
2406
|
+
if (repoCheck.detail) console.log(pc.dim(` ${repoCheck.detail}`));
|
|
1976
2407
|
hasWarnings = true;
|
|
1977
2408
|
}
|
|
1978
2409
|
console.log();
|
|
@@ -1983,18 +2414,14 @@ const statusCommand = defineCommand({
|
|
|
1983
2414
|
}
|
|
1984
2415
|
if (handle) console.log(` ${INFO} Handle: ${pc.cyan(`@${handle}`)}`);
|
|
1985
2416
|
if (did) {
|
|
1986
|
-
const
|
|
1987
|
-
|
|
1988
|
-
if (
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
console.log(pc.dim(` Expected: ${expectedEndpoint}`));
|
|
1995
|
-
console.log(pc.dim(` Got: ${resolved.pdsEndpoint}`));
|
|
1996
|
-
hasErrors = true;
|
|
1997
|
-
}
|
|
2417
|
+
const didCheck = await checkDidResolution(client, did, pdsHostname);
|
|
2418
|
+
if (didCheck.ok) console.log(` ${CHECK} DID resolves to this PDS (via ${didCheck.resolveMethod})`);
|
|
2419
|
+
else if (didCheck.pdsEndpoint) {
|
|
2420
|
+
console.log(` ${CROSS} DID resolves to different PDS`);
|
|
2421
|
+
console.log(pc.dim(` Resolved via: ${didCheck.resolveMethod}`));
|
|
2422
|
+
console.log(pc.dim(` Expected: https://${pdsHostname}`));
|
|
2423
|
+
console.log(pc.dim(` Got: ${didCheck.pdsEndpoint}`));
|
|
2424
|
+
hasErrors = true;
|
|
1998
2425
|
} else {
|
|
1999
2426
|
console.log(` ${WARN} Could not resolve DID`);
|
|
2000
2427
|
if (did.startsWith("did:plc:")) console.log(pc.dim(" Check plc.directory or update DID document"));
|
|
@@ -2006,19 +2433,13 @@ const statusCommand = defineCommand({
|
|
|
2006
2433
|
hasWarnings = true;
|
|
2007
2434
|
}
|
|
2008
2435
|
if (handle) {
|
|
2009
|
-
const
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
if (httpValid || dnsValid) {
|
|
2013
|
-
const methods = [];
|
|
2014
|
-
if (dnsValid) methods.push("DNS");
|
|
2015
|
-
if (httpValid) methods.push("HTTP");
|
|
2016
|
-
console.log(` ${CHECK} Handle verified via ${methods.join(" + ")}`);
|
|
2017
|
-
} else if (httpDid || dnsDid) {
|
|
2436
|
+
const handleCheck = await checkHandleResolutionDetailed(client, handle, did);
|
|
2437
|
+
if (handleCheck.ok) console.log(` ${CHECK} Handle verified via ${handleCheck.methods.join(" + ")}`);
|
|
2438
|
+
else if (handleCheck.httpDid || handleCheck.dnsDid) {
|
|
2018
2439
|
console.log(` ${CROSS} Handle resolves to different DID`);
|
|
2019
2440
|
console.log(pc.dim(` Expected: ${did}`));
|
|
2020
|
-
if (httpDid) console.log(pc.dim(` HTTP well-known: ${httpDid}`));
|
|
2021
|
-
if (dnsDid) console.log(pc.dim(` DNS TXT: ${dnsDid}`));
|
|
2441
|
+
if (handleCheck.httpDid) console.log(pc.dim(` HTTP well-known: ${handleCheck.httpDid}`));
|
|
2442
|
+
if (handleCheck.dnsDid) console.log(pc.dim(` DNS TXT: ${handleCheck.dnsDid}`));
|
|
2022
2443
|
hasErrors = true;
|
|
2023
2444
|
} else {
|
|
2024
2445
|
console.log(` ${WARN} Handle not resolving`);
|
|
@@ -2030,7 +2451,8 @@ const statusCommand = defineCommand({
|
|
|
2030
2451
|
console.log();
|
|
2031
2452
|
if (status.expectedBlobs > 0) {
|
|
2032
2453
|
console.log(pc.bold("Blobs"));
|
|
2033
|
-
|
|
2454
|
+
const blobCheck = checkBlobsImported(status);
|
|
2455
|
+
if (blobCheck.ok) console.log(` ${CHECK} ${blobCheck.message}`);
|
|
2034
2456
|
else {
|
|
2035
2457
|
const missing = status.expectedBlobs - status.importedBlobs;
|
|
2036
2458
|
console.log(` ${WARN} ${status.importedBlobs}/${status.expectedBlobs} blobs imported (${missing} missing)`);
|
|
@@ -2039,11 +2461,33 @@ const statusCommand = defineCommand({
|
|
|
2039
2461
|
console.log();
|
|
2040
2462
|
}
|
|
2041
2463
|
console.log(pc.bold("Federation"));
|
|
2042
|
-
if (did)
|
|
2043
|
-
|
|
2044
|
-
console.log(` ${
|
|
2045
|
-
|
|
2046
|
-
|
|
2464
|
+
if (did) {
|
|
2465
|
+
const appViewCheck = await checkAppViewIndexing(client, did);
|
|
2466
|
+
if (appViewCheck.ok) console.log(` ${CHECK} ${appViewCheck.message}`);
|
|
2467
|
+
else {
|
|
2468
|
+
console.log(` ${WARN} ${appViewCheck.message}`);
|
|
2469
|
+
if (appViewCheck.detail) console.log(pc.dim(` ${appViewCheck.detail}`));
|
|
2470
|
+
hasWarnings = true;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
if (pdsHostname) {
|
|
2474
|
+
const relayStatuses = await client.getAllRelayHostStatus(pdsHostname);
|
|
2475
|
+
const hasActiveRelay = relayStatuses.some((r) => r.status === "active");
|
|
2476
|
+
const hasBannedRelay = relayStatuses.some((r) => r.status === "banned");
|
|
2477
|
+
const needsCrawl = relayStatuses.length === 0 || relayStatuses.every((r) => r.status === "idle" || r.status === "offline");
|
|
2478
|
+
if (relayStatuses.length === 0) console.log(` ${WARN} No relays have crawled this PDS yet`);
|
|
2479
|
+
else for (const relayStatus of relayStatuses) {
|
|
2480
|
+
const relayName = relayStatus.relay.includes("us-west") ? "us-west" : "us-east";
|
|
2481
|
+
const statusIcon = relayStatus.status === "active" ? CHECK : relayStatus.status === "banned" ? CROSS : WARN;
|
|
2482
|
+
console.log(` ${statusIcon} Relay ${relayName}: ${relayStatus.status}${relayStatus.accountCount !== void 0 ? ` (${relayStatus.accountCount} accounts, seq: ${relayStatus.seq ?? "none"})` : ""}`);
|
|
2483
|
+
}
|
|
2484
|
+
if (hasBannedRelay && !hasActiveRelay) {
|
|
2485
|
+
console.log(` ${CROSS} PDS is banned from all relays`);
|
|
2486
|
+
hasErrors = true;
|
|
2487
|
+
} else if (needsCrawl) {
|
|
2488
|
+
console.log(pc.dim(" Run 'pds activate' or 'pds emit-identity' to request a crawl"));
|
|
2489
|
+
hasWarnings = true;
|
|
2490
|
+
}
|
|
2047
2491
|
}
|
|
2048
2492
|
try {
|
|
2049
2493
|
const firehose = await client.getFirehoseStatus();
|
|
@@ -2068,6 +2512,80 @@ const statusCommand = defineCommand({
|
|
|
2068
2512
|
}
|
|
2069
2513
|
});
|
|
2070
2514
|
|
|
2515
|
+
//#endregion
|
|
2516
|
+
//#region src/cli/commands/emit-identity.ts
|
|
2517
|
+
/**
|
|
2518
|
+
* Emit identity command - notifies relays to refresh handle verification
|
|
2519
|
+
*/
|
|
2520
|
+
const emitIdentityCommand = defineCommand({
|
|
2521
|
+
meta: {
|
|
2522
|
+
name: "emit-identity",
|
|
2523
|
+
description: "Emit an identity event to notify relays to refresh handle verification"
|
|
2524
|
+
},
|
|
2525
|
+
args: { dev: {
|
|
2526
|
+
type: "boolean",
|
|
2527
|
+
description: "Target local development server instead of production",
|
|
2528
|
+
default: false
|
|
2529
|
+
} },
|
|
2530
|
+
async run({ args }) {
|
|
2531
|
+
const isDev = args.dev;
|
|
2532
|
+
p.intro("🦋 Emit Identity Event");
|
|
2533
|
+
const vars = getVars();
|
|
2534
|
+
let targetUrl;
|
|
2535
|
+
try {
|
|
2536
|
+
targetUrl = getTargetUrl(isDev, vars.PDS_HOSTNAME);
|
|
2537
|
+
} catch (err) {
|
|
2538
|
+
p.log.error(err instanceof Error ? err.message : "Configuration error");
|
|
2539
|
+
p.log.info("Run 'pds init' first to configure your PDS.");
|
|
2540
|
+
process.exit(1);
|
|
2541
|
+
}
|
|
2542
|
+
const targetDomain = getDomain(targetUrl);
|
|
2543
|
+
const wranglerVars = getVars();
|
|
2544
|
+
const config = {
|
|
2545
|
+
...readDevVars(),
|
|
2546
|
+
...wranglerVars
|
|
2547
|
+
};
|
|
2548
|
+
const authToken = config.AUTH_TOKEN;
|
|
2549
|
+
if (!authToken) {
|
|
2550
|
+
p.log.error("No AUTH_TOKEN found. Run 'pds init' first.");
|
|
2551
|
+
p.outro("Cancelled.");
|
|
2552
|
+
process.exit(1);
|
|
2553
|
+
}
|
|
2554
|
+
const client = new PDSClient(targetUrl, authToken);
|
|
2555
|
+
const spinner = p.spinner();
|
|
2556
|
+
spinner.start(`Checking PDS at ${targetDomain}...`);
|
|
2557
|
+
if (!await client.healthCheck()) {
|
|
2558
|
+
spinner.stop(`PDS not responding at ${targetDomain}`);
|
|
2559
|
+
p.log.error(`Your PDS isn't responding at ${targetUrl}`);
|
|
2560
|
+
if (!isDev) p.log.info("Make sure your worker is deployed: wrangler deploy");
|
|
2561
|
+
p.outro("Cancelled.");
|
|
2562
|
+
process.exit(1);
|
|
2563
|
+
}
|
|
2564
|
+
spinner.stop(`Connected to ${targetDomain}`);
|
|
2565
|
+
spinner.start("Emitting identity event...");
|
|
2566
|
+
try {
|
|
2567
|
+
const result = await client.emitIdentity();
|
|
2568
|
+
spinner.stop(`Identity event emitted (seq: ${result.seq})`);
|
|
2569
|
+
} catch (err) {
|
|
2570
|
+
spinner.stop("Failed to emit identity event");
|
|
2571
|
+
p.log.error(err instanceof Error ? err.message : "Could not emit identity event");
|
|
2572
|
+
p.outro("Failed.");
|
|
2573
|
+
process.exit(1);
|
|
2574
|
+
}
|
|
2575
|
+
const pdsHostname = config.PDS_HOSTNAME;
|
|
2576
|
+
if (pdsHostname && !isDev) {
|
|
2577
|
+
spinner.start("Requesting crawl from relay...");
|
|
2578
|
+
if (await client.requestCrawl(pdsHostname)) spinner.stop("Crawl requested");
|
|
2579
|
+
else {
|
|
2580
|
+
spinner.stop("Could not request crawl");
|
|
2581
|
+
p.log.warn("The relay may not pick up the identity change immediately.");
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
p.log.success("Relays have been notified to refresh your handle verification.");
|
|
2585
|
+
p.outro("Done!");
|
|
2586
|
+
}
|
|
2587
|
+
});
|
|
2588
|
+
|
|
2071
2589
|
//#endregion
|
|
2072
2590
|
//#region src/cli/index.ts
|
|
2073
2591
|
/**
|
|
@@ -2085,7 +2603,8 @@ runMain(defineCommand({
|
|
|
2085
2603
|
migrate: migrateCommand,
|
|
2086
2604
|
activate: activateCommand,
|
|
2087
2605
|
deactivate: deactivateCommand,
|
|
2088
|
-
status: statusCommand
|
|
2606
|
+
status: statusCommand,
|
|
2607
|
+
"emit-identity": emitIdentityCommand
|
|
2089
2608
|
}
|
|
2090
2609
|
}));
|
|
2091
2610
|
|