OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface commits / 258a245

published is not reachable — the card says so, and offers the fix
A mint is P2P-only: the genesis carries alsoKnownAs: [] and services: {}, so a DID can be published to the global directory and resolve for nobody. The card called that state 'Published' and stopped, which is why it looked finished. It now distinguishes published from reachable, and /did/carry does both halves in one call — ask a bridge to carry it, then put the granted handle and endpoint on-chain. The screen names which half is permanent: the bridge can let you go, the PLC append cannot be undone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
258a2456759cecbecdd840f560215596466aa6ce
by plankatron <fleeky@gmail.com> · 2026-09-11T19:14:49.000Z

Changed files (4) +326 -223

.pgh-lock.json +187 -222
……@@ -1,9 +1,9 @@
11{
22 "name": "favela-surface",
3 "version": "0.0.47",
3 "version": "0.0.49",
44 "runtime": "bare",
5 "rootTreeHash": "1a286aa160aa8fe603b8145835714a40096dd917091952328f54440b37000783",
6 "publishedAt": "2026-09-08T14:50:30.026Z",
5 "rootTreeHash": "12189a4f4b30d49d3a13efc3ae7237579d611147d33dab0254fdab45cd7adb8e",
6 "publishedAt": "2026-09-10T00:03:36.814Z",
77 "deps": [
88 {
99 "name": "@jridgewell/resolve-uri",
……@@ -782,9 +782,9 @@
782782 },
783783 {
784784 "name": "favela-markdown",
785 "version": "0.1.6",
786 "tree": "97d64cb2674377910d3ec28f3f4246d7e3fbc1b9b06b8b9d1ef6360cc0765569",
787 "normHash": "853f6fe2c24cea0c956653eaa7d5a13b7feca966cad5c9a6164c2dc1ff324881",
785 "version": "0.2.0",
786 "tree": "e980c91c65708beb2d24964f4f8bce19d01f9783d1d93e4eff8674851df64611",
787 "normHash": "2b6a91ad3e40196bc8a2bed0be0d54af70e365e9159504e3cb86e73f034b8c5f",
788788 "workspace": true
789789 },
790790 {
……@@ -1313,11 +1313,6 @@
13131313 "newVersion": "1.6.0",
13141314 "newTree": "b6396de092d11e559d109b0dea7995f340b7959c4efeb0baa06b091f99a43245",
13151315 "existing": [
1316 {
1317 "appName": "ap-bridge",
1318 "version": "1.5.5",
1319 "tree": "6bfc474f65e0ad253537aed3c3117185db2de168866738eca197e1feff6d5f92"
1320 },
13211316 {
13221317 "appName": "atproto-bridge",
13231318 "version": "1.5.5",
……@@ -1357,10 +1352,15 @@
13571352 "appName": "favela-bridge",
13581353 "version": "1.5.5",
13591354 "tree": "6bfc474f65e0ad253537aed3c3117185db2de168866738eca197e1feff6d5f92"
1355 },
1356 {
1357 "appName": "blender-repo-sync",
1358 "version": "1.5.5",
1359 "tree": "6bfc474f65e0ad253537aed3c3117185db2de168866738eca197e1feff6d5f92"
13601360 }
13611361 ],
1362 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1363 "acceptedAt": "2026-09-08T14:50:30.040Z"
1362 "reason": "dep version-splits only; 0 code-differs",
1363 "acceptedAt": "2026-09-10T00:03:36.827Z"
13641364 },
13651365 {
13661366 "type": "VERSION_CONFLICT",
……@@ -1374,8 +1374,8 @@
13741374 "tree": "edd1c368bdb9167c9094892aef3dd71e9294fb7cf8659c53496fac9eb2d21f43"
13751375 }
13761376 ],
1377 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1378 "acceptedAt": "2026-09-08T14:50:30.040Z"
1377 "reason": "dep version-splits only; 0 code-differs",
1378 "acceptedAt": "2026-09-10T00:03:36.827Z"
13791379 },
13801380 {
13811381 "type": "VERSION_CONFLICT",
……@@ -1424,8 +1424,8 @@
14241424 "tree": "d787b0d5e4be01882bf1bfe893b91c856a58d641158f65d786669af56b8822c7"
14251425 }
14261426 ],
1427 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1428 "acceptedAt": "2026-09-08T14:50:30.040Z"
1427 "reason": "dep version-splits only; 0 code-differs",
1428 "acceptedAt": "2026-09-10T00:03:36.827Z"
14291429 },
14301430 {
14311431 "type": "VERSION_CONFLICT",
……@@ -1433,11 +1433,6 @@
14331433 "newVersion": "3.7.1",
14341434 "newTree": "5b662871145437a17e36c1dbebd64fc6e29be649b168ffb7638d3c5eaa781443",
14351435 "existing": [
1436 {
1437 "appName": "ap-bridge",
1438 "version": "3.6.1",
1439 "tree": "6bb5233025d1c30e4f181e29b6ab5af549d8909c7070c7b4438b30f1a4e76ce2"
1440 },
14411436 {
14421437 "appName": "atproto-bridge",
14431438 "version": "3.6.1",
……@@ -1474,8 +1469,8 @@
14741469 "tree": "6bb5233025d1c30e4f181e29b6ab5af549d8909c7070c7b4438b30f1a4e76ce2"
14751470 }
14761471 ],
1477 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1478 "acceptedAt": "2026-09-08T14:50:30.040Z"
1472 "reason": "dep version-splits only; 0 code-differs",
1473 "acceptedAt": "2026-09-10T00:03:36.827Z"
14791474 },
14801475 {
14811476 "type": "VERSION_CONFLICT",
……@@ -1489,8 +1484,8 @@
14891484 "tree": "58c0bf8698af19464d0ee8354a77ed1ac96d3a5fa18aa4e794686cfbbf080e5d"
14901485 }
14911486 ],
1492 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1493 "acceptedAt": "2026-09-08T14:50:30.040Z"
1487 "reason": "dep version-splits only; 0 code-differs",
1488 "acceptedAt": "2026-09-10T00:03:36.827Z"
14941489 },
14951490 {
14961491 "type": "VERSION_CONFLICT",
……@@ -1504,8 +1499,8 @@
15041499 "tree": "34082170af8eaa06400c102103b83c05d45974918552e7cdf51b867ab20a517e"
15051500 }
15061501 ],
1507 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1508 "acceptedAt": "2026-09-08T14:50:30.040Z"
1502 "reason": "dep version-splits only; 0 code-differs",
1503 "acceptedAt": "2026-09-10T00:03:36.827Z"
15091504 },
15101505 {
15111506 "type": "VERSION_CONFLICT",
……@@ -1519,8 +1514,8 @@
15191514 "tree": "bde476b9d591d94c4a2c7f6c4fa3e922b8719839122db25fdc204ac9398b38af"
15201515 }
15211516 ],
1522 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1523 "acceptedAt": "2026-09-08T14:50:30.040Z"
1517 "reason": "dep version-splits only; 0 code-differs",
1518 "acceptedAt": "2026-09-10T00:03:36.827Z"
15241519 },
15251520 {
15261521 "type": "VERSION_CONFLICT",
……@@ -1528,11 +1523,6 @@
15281523 "newVersion": "2.2.0",
15291524 "newTree": "a49b9c4ace4ade9435e530c82694bf39e10e0176475ae6b4270dec913bf6c5ef",
15301525 "existing": [
1531 {
1532 "appName": "ap-bridge",
1533 "version": "2.1.4",
1534 "tree": "b99a90bd799b25bf856c200d6473514c7ae5e3c334b806de938dc75464715620"
1535 },
15361526 {
15371527 "appName": "atproto-bridge",
15381528 "version": "2.1.4",
……@@ -1572,10 +1562,15 @@
15721562 "appName": "favela-bridge",
15731563 "version": "2.1.4",
15741564 "tree": "b99a90bd799b25bf856c200d6473514c7ae5e3c334b806de938dc75464715620"
1565 },
1566 {
1567 "appName": "blender-repo-sync",
1568 "version": "2.1.4",
1569 "tree": "b99a90bd799b25bf856c200d6473514c7ae5e3c334b806de938dc75464715620"
15751570 }
15761571 ],
1577 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1578 "acceptedAt": "2026-09-08T14:50:30.040Z"
1572 "reason": "dep version-splits only; 0 code-differs",
1573 "acceptedAt": "2026-09-10T00:03:36.827Z"
15791574 },
15801575 {
15811576 "type": "VERSION_CONFLICT",
……@@ -1614,8 +1609,8 @@
16141609 "tree": "e69de4dbef07248b4dffaccc6f4ce93cd567961780d46d60e944db8a9a5b5c95"
16151610 }
16161611 ],
1617 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1618 "acceptedAt": "2026-09-08T14:50:30.040Z"
1612 "reason": "dep version-splits only; 0 code-differs",
1613 "acceptedAt": "2026-09-10T00:03:36.827Z"
16191614 },
16201615 {
16211616 "type": "VERSION_CONFLICT",
……@@ -1664,8 +1659,8 @@
16641659 "tree": "277db613fdba514bd8ece9f0c20680794a9deedf5dd92456baff3072b80f9e01"
16651660 }
16661661 ],
1667 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1668 "acceptedAt": "2026-09-08T14:50:30.040Z"
1662 "reason": "dep version-splits only; 0 code-differs",
1663 "acceptedAt": "2026-09-10T00:03:36.827Z"
16691664 },
16701665 {
16711666 "type": "VERSION_CONFLICT",
……@@ -1709,8 +1704,8 @@
17091704 "tree": "122e16ca5645e4fda16561939b4365069a536b6a26488e6634553dc6f6c3512e"
17101705 }
17111706 ],
1712 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1713 "acceptedAt": "2026-09-08T14:50:30.040Z"
1707 "reason": "dep version-splits only; 0 code-differs",
1708 "acceptedAt": "2026-09-10T00:03:36.827Z"
17141709 },
17151710 {
17161711 "type": "VERSION_CONFLICT",
……@@ -1718,11 +1713,6 @@
17181713 "newVersion": "2.1.2",
17191714 "newTree": "623bbbece48d0415c906980604a2d46515e0a7b1aeb63516eae5ceb981a27bdd",
17201715 "existing": [
1721 {
1722 "appName": "ap-bridge",
1723 "version": "2.1.1",
1724 "tree": "f7441d03a850f3516f501ca3669fb9c0d5c509cdc7500a9157e02f3893bf91aa"
1725 },
17261716 {
17271717 "appName": "atproto-bridge",
17281718 "version": "2.1.1",
……@@ -1769,8 +1759,8 @@
17691759 "tree": "f7441d03a850f3516f501ca3669fb9c0d5c509cdc7500a9157e02f3893bf91aa"
17701760 }
17711761 ],
1772 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1773 "acceptedAt": "2026-09-08T14:50:30.040Z"
1762 "reason": "dep version-splits only; 0 code-differs",
1763 "acceptedAt": "2026-09-10T00:03:36.827Z"
17741764 },
17751765 {
17761766 "type": "VERSION_CONFLICT",
……@@ -1778,11 +1768,6 @@
17781768 "newVersion": "2.1.4",
17791769 "newTree": "e6991084a57472974a7f19d371cdfa226c28bd92be2d3b5a7ba38eabba8b3bb5",
17801770 "existing": [
1781 {
1782 "appName": "ap-bridge",
1783 "version": "1.1.5",
1784 "tree": "7346777d1da99cb88743066eed85f462a1a41fc5d13cbe01317abded566d6edd"
1785 },
17861771 {
17871772 "appName": "atproto-bridge",
17881773 "version": "1.1.5",
……@@ -1822,10 +1807,15 @@
18221807 "appName": "favela-bridge",
18231808 "version": "1.1.5",
18241809 "tree": "7346777d1da99cb88743066eed85f462a1a41fc5d13cbe01317abded566d6edd"
1810 },
1811 {
1812 "appName": "blender-repo-sync",
1813 "version": "1.1.5",
1814 "tree": "7346777d1da99cb88743066eed85f462a1a41fc5d13cbe01317abded566d6edd"
18251815 }
18261816 ],
1827 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1828 "acceptedAt": "2026-09-08T14:50:30.040Z"
1817 "reason": "dep version-splits only; 0 code-differs",
1818 "acceptedAt": "2026-09-10T00:03:36.827Z"
18291819 },
18301820 {
18311821 "type": "VERSION_CONFLICT",
……@@ -1833,11 +1823,6 @@
18331823 "newVersion": "4.6.1",
18341824 "newTree": "ad81cb00dc100cbacbe692462fefc6cd1d676e4b6022e3b9fa2d9294a4461aac",
18351825 "existing": [
1836 {
1837 "appName": "ap-bridge",
1838 "version": "4.5.7",
1839 "tree": "5a01066123c99d1e6e0ddb8a709deb5a794c27764a120a39165034cf36a2d02a"
1840 },
18411826 {
18421827 "appName": "atproto-bridge",
18431828 "version": "4.5.7",
……@@ -1877,10 +1862,15 @@
18771862 "appName": "favela-bridge",
18781863 "version": "4.5.7",
18791864 "tree": "5a01066123c99d1e6e0ddb8a709deb5a794c27764a120a39165034cf36a2d02a"
1865 },
1866 {
1867 "appName": "blender-repo-sync",
1868 "version": "4.5.7",
1869 "tree": "5a01066123c99d1e6e0ddb8a709deb5a794c27764a120a39165034cf36a2d02a"
18801870 }
18811871 ],
1882 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1883 "acceptedAt": "2026-09-08T14:50:30.040Z"
1872 "reason": "dep version-splits only; 0 code-differs",
1873 "acceptedAt": "2026-09-10T00:03:36.827Z"
18841874 },
18851875 {
18861876 "type": "VERSION_CONFLICT",
……@@ -1888,11 +1878,6 @@
18881878 "newVersion": "3.1.0",
18891879 "newTree": "5e9cf8230c28d6b667d121cb23a5202b5d5d44e12dbeef0a7d6fbcc55621bb3d",
18901880 "existing": [
1891 {
1892 "appName": "ap-bridge",
1893 "version": "3.0.0",
1894 "tree": "6868d7a4dfe1fc9397a280931f86de7eb6ff7c64a380f9a41fb397f859488dbb"
1895 },
18961881 {
18971882 "appName": "atproto-bridge",
18981883 "version": "3.0.0",
……@@ -1932,10 +1917,15 @@
19321917 "appName": "favela-bridge",
19331918 "version": "3.0.0",
19341919 "tree": "6868d7a4dfe1fc9397a280931f86de7eb6ff7c64a380f9a41fb397f859488dbb"
1920 },
1921 {
1922 "appName": "blender-repo-sync",
1923 "version": "3.0.0",
1924 "tree": "6868d7a4dfe1fc9397a280931f86de7eb6ff7c64a380f9a41fb397f859488dbb"
19351925 }
19361926 ],
1937 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1938 "acceptedAt": "2026-09-08T14:50:30.040Z"
1927 "reason": "dep version-splits only; 0 code-differs",
1928 "acceptedAt": "2026-09-10T00:03:36.827Z"
19391929 },
19401930 {
19411931 "type": "VERSION_CONFLICT",
……@@ -1943,11 +1933,6 @@
19431933 "newVersion": "3.1.10",
19441934 "newTree": "f43421419fb851f1bf8fd6f284e23d9f8b5ff2bcb320ac71dcf420b261dc7264",
19451935 "existing": [
1946 {
1947 "appName": "ap-bridge",
1948 "version": "3.1.4",
1949 "tree": "f34f3df7b3c33ef17643c8133319fd92de6acb503fa8923b8f829cc29bfd9969"
1950 },
19511936 {
19521937 "appName": "atproto-bridge",
19531938 "version": "3.1.4",
……@@ -1994,8 +1979,8 @@
19941979 "tree": "f34f3df7b3c33ef17643c8133319fd92de6acb503fa8923b8f829cc29bfd9969"
19951980 }
19961981 ],
1997 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
1998 "acceptedAt": "2026-09-08T14:50:30.040Z"
1982 "reason": "dep version-splits only; 0 code-differs",
1983 "acceptedAt": "2026-09-10T00:03:36.827Z"
19991984 },
20001985 {
20011986 "type": "VERSION_CONFLICT",
……@@ -2022,10 +2007,15 @@
20222007 "appName": "atproto-pds",
20232008 "version": "4.0.3",
20242009 "tree": "abcf1f5e9754987f9ce5cdfccc98548652b1242fb43a19669f874c8bd76e4d00"
2010 },
2011 {
2012 "appName": "blender-repo-sync",
2013 "version": "6.0.2",
2014 "tree": "dacb5f2689ca922d0431d9958d29e8c070a472355bd9b3fe3ca112be5c159f23"
20252015 }
20262016 ],
2027 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2028 "acceptedAt": "2026-09-08T14:50:30.040Z"
2017 "reason": "dep version-splits only; 0 code-differs",
2018 "acceptedAt": "2026-09-10T00:03:36.827Z"
20292019 },
20302020 {
20312021 "type": "VERSION_CONFLICT",
……@@ -2052,10 +2042,15 @@
20522042 "appName": "atproto-pds",
20532043 "version": "6.2.0",
20542044 "tree": "6061470b9f36b6509528bd7d286ef9244748e6954aca803deb43b8827a66bae2"
2045 },
2046 {
2047 "appName": "blender-repo-sync",
2048 "version": "6.2.1",
2049 "tree": "d678235d9563addbff0dea060f7739123bb6bc239e344b2fec5db536e2340797"
20552050 }
20562051 ],
2057 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2058 "acceptedAt": "2026-09-08T14:50:30.040Z"
2052 "reason": "dep version-splits only; 0 code-differs",
2053 "acceptedAt": "2026-09-10T00:03:36.827Z"
20592054 },
20602055 {
20612056 "type": "VERSION_CONFLICT",
……@@ -2063,11 +2058,6 @@
20632058 "newVersion": "1.6.6",
20642059 "newTree": "196ef311029d1ff5524e5c763f050d67c2db3e6c026a3b2c7262ff922f52c487",
20652060 "existing": [
2066 {
2067 "appName": "ap-bridge",
2068 "version": "1.6.3",
2069 "tree": "3629f8e2e4cb404a3b236f94f9ab154c5fa833bdea102ee9cb578b4467f20803"
2070 },
20712061 {
20722062 "appName": "atproto-bridge",
20732063 "version": "1.6.0",
……@@ -2107,10 +2097,15 @@
21072097 "appName": "favela-bridge",
21082098 "version": "1.6.0",
21092099 "tree": "aa34544c9ac2bbe3ee0e1cfaddb76ce9e2e6e9e15130967a8aa50f6836c97b47"
2100 },
2101 {
2102 "appName": "blender-repo-sync",
2103 "version": "1.5.2",
2104 "tree": "0423999b6587f905fd2e8cb7768e5d0587da0489595e8dd543497e3604f35ff1"
21102105 }
21112106 ],
2112 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2113 "acceptedAt": "2026-09-08T14:50:30.040Z"
2107 "reason": "dep version-splits only; 0 code-differs",
2108 "acceptedAt": "2026-09-10T00:03:36.827Z"
21142109 },
21152110 {
21162111 "type": "VERSION_CONFLICT",
……@@ -2118,11 +2113,6 @@
21182113 "newVersion": "1.12.5",
21192114 "newTree": "9386fa8b9509fda8b231ae9fd0d7672da1eab57959333e06ee29ba583e60bb5b",
21202115 "existing": [
2121 {
2122 "appName": "ap-bridge",
2123 "version": "1.12.4",
2124 "tree": "2c5df3de8e036cd2844ee7d2cfb1faa43c5b45c19a4f0a01914f5ca093efc59c"
2125 },
21262116 {
21272117 "appName": "atproto-bridge",
21282118 "version": "1.12.2",
……@@ -2169,8 +2159,8 @@
21692159 "tree": "d38fbe2473ea0a356bf959bb395e5871c51a5bba1d86a5400041e2d57f2ca519"
21702160 }
21712161 ],
2172 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2173 "acceptedAt": "2026-09-08T14:50:30.040Z"
2162 "reason": "dep version-splits only; 0 code-differs",
2163 "acceptedAt": "2026-09-10T00:03:36.827Z"
21742164 },
21752165 {
21762166 "type": "VERSION_CONFLICT",
……@@ -2212,10 +2202,15 @@
22122202 "appName": "atproto-pds",
22132203 "version": "2.3.2",
22142204 "tree": "cc3134354105b041a80d3fc6f6fc238cd6839f1a413ad846d1f47c1b95d5e098"
2205 },
2206 {
2207 "appName": "blender-repo-sync",
2208 "version": "2.3.2",
2209 "tree": "cc3134354105b041a80d3fc6f6fc238cd6839f1a413ad846d1f47c1b95d5e098"
22152210 }
22162211 ],
2217 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2218 "acceptedAt": "2026-09-08T14:50:30.040Z"
2212 "reason": "dep version-splits only; 0 code-differs",
2213 "acceptedAt": "2026-09-10T00:03:36.827Z"
22192214 },
22202215 {
22212216 "type": "VERSION_CONFLICT",
……@@ -2244,8 +2239,8 @@
22442239 "tree": "ab13549b2fb10430420d3c21cebeef3f908867b1f19e73f837f7be3e9d843e34"
22452240 }
22462241 ],
2247 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2248 "acceptedAt": "2026-09-08T14:50:30.040Z"
2242 "reason": "dep version-splits only; 0 code-differs",
2243 "acceptedAt": "2026-09-10T00:03:36.827Z"
22492244 },
22502245 {
22512246 "type": "VERSION_CONFLICT",
……@@ -2294,8 +2289,8 @@
22942289 "tree": "910e863bbacee70ecac40e5c2b2c6c968a84408b12a9299d91f06adfa5b85df6"
22952290 }
22962291 ],
2297 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2298 "acceptedAt": "2026-09-08T14:50:30.040Z"
2292 "reason": "dep version-splits only; 0 code-differs",
2293 "acceptedAt": "2026-09-10T00:03:36.827Z"
22992294 },
23002295 {
23012296 "type": "VERSION_CONFLICT",
……@@ -2303,11 +2298,6 @@
23032298 "newVersion": "4.3.1",
23042299 "newTree": "08013f3f76e93f236b04c5a804dfd12debdc44bc2b5a5a5010f190f96ad682ec",
23052300 "existing": [
2306 {
2307 "appName": "ap-bridge",
2308 "version": "4.2.3",
2309 "tree": "dfa7aa8ed70eff23a8086daa2205b79f17cb84807e6472e9650f182e730e83f4"
2310 },
23112301 {
23122302 "appName": "atproto-bridge",
23132303 "version": "4.2.2",
……@@ -2354,8 +2344,8 @@
23542344 "tree": "fbe0c6c38f64accca0f1110df8a5170041566c179c5f3d91b965562ce7fab7f9"
23552345 }
23562346 ],
2357 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2358 "acceptedAt": "2026-09-08T14:50:30.040Z"
2347 "reason": "dep version-splits only; 0 code-differs",
2348 "acceptedAt": "2026-09-10T00:03:36.827Z"
23592349 },
23602350 {
23612351 "type": "VERSION_CONFLICT",
……@@ -2389,8 +2379,8 @@
23892379 "tree": "82d03ae511b2169f36316ad261a9de23ccaa4e77fda54d295a60ea780f4541e4"
23902380 }
23912381 ],
2392 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2393 "acceptedAt": "2026-09-08T14:50:30.040Z"
2382 "reason": "dep version-splits only; 0 code-differs",
2383 "acceptedAt": "2026-09-10T00:03:36.827Z"
23942384 },
23952385 {
23962386 "type": "VERSION_CONFLICT",
……@@ -2414,8 +2404,8 @@
24142404 "tree": "4b9204b771f3d98e1d2dbf571cec2b2cfe285de1966cf5c8f12feb5de152f445"
24152405 }
24162406 ],
2417 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2418 "acceptedAt": "2026-09-08T14:50:30.040Z"
2407 "reason": "dep version-splits only; 0 code-differs",
2408 "acceptedAt": "2026-09-10T00:03:36.827Z"
24192409 },
24202410 {
24212411 "type": "VERSION_CONFLICT",
……@@ -2454,8 +2444,8 @@
24542444 "tree": "bb24c2a35a269fd4db35454ee238c1b84eee9a1258e46a742d0fd40d23fa2f51"
24552445 }
24562446 ],
2457 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2458 "acceptedAt": "2026-09-08T14:50:30.040Z"
2447 "reason": "dep version-splits only; 0 code-differs",
2448 "acceptedAt": "2026-09-10T00:03:36.827Z"
24592449 },
24602450 {
24612451 "type": "VERSION_CONFLICT",
……@@ -2494,8 +2484,8 @@
24942484 "tree": "1ef15539afb1b1e2b17d363e9de340e9427ced3ce58165c22f722fd60579649d"
24952485 }
24962486 ],
2497 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2498 "acceptedAt": "2026-09-08T14:50:30.040Z"
2487 "reason": "dep version-splits only; 0 code-differs",
2488 "acceptedAt": "2026-09-10T00:03:36.827Z"
24992489 },
25002490 {
25012491 "type": "VERSION_CONFLICT",
……@@ -2544,8 +2534,8 @@
25442534 "tree": "517fda54c5edc58453377c1a627af937ddb2a753d725a99b7daef5bdd344f482"
25452535 }
25462536 ],
2547 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2548 "acceptedAt": "2026-09-08T14:50:30.040Z"
2537 "reason": "dep version-splits only; 0 code-differs",
2538 "acceptedAt": "2026-09-10T00:03:36.827Z"
25492539 },
25502540 {
25512541 "type": "VERSION_CONFLICT",
……@@ -2569,8 +2559,8 @@
25692559 "tree": "bdebba5a532ce4846b49f1e5ffad774becfc44182d0c3737f7e441ab42f4c43d"
25702560 }
25712561 ],
2572 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2573 "acceptedAt": "2026-09-08T14:50:30.040Z"
2562 "reason": "dep version-splits only; 0 code-differs",
2563 "acceptedAt": "2026-09-10T00:03:36.827Z"
25742564 },
25752565 {
25762566 "type": "VERSION_CONFLICT",
……@@ -2578,11 +2568,6 @@
25782568 "newVersion": "6.1.0",
25792569 "newTree": "d31788ffa334976153023c6de84e5020b2009f51f9d472d0c2f09a13a53fc2b6",
25802570 "existing": [
2581 {
2582 "appName": "ap-bridge",
2583 "version": "5.2.3",
2584 "tree": "dc68280c6e1c21dd901373288671cf8d9d9dc9db4845721fdc40ba54eaa12c67"
2585 },
25862571 {
25872572 "appName": "atproto-bridge",
25882573 "version": "5.2.3",
……@@ -2602,10 +2587,15 @@
26022587 "appName": "favela-bridge",
26032588 "version": "5.2.3",
26042589 "tree": "dc68280c6e1c21dd901373288671cf8d9d9dc9db4845721fdc40ba54eaa12c67"
2590 },
2591 {
2592 "appName": "blender-repo-sync",
2593 "version": "5.2.3",
2594 "tree": "dc68280c6e1c21dd901373288671cf8d9d9dc9db4845721fdc40ba54eaa12c67"
26052595 }
26062596 ],
2607 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2608 "acceptedAt": "2026-09-08T14:50:30.040Z"
2597 "reason": "dep version-splits only; 0 code-differs",
2598 "acceptedAt": "2026-09-10T00:03:36.827Z"
26092599 },
26102600 {
26112601 "type": "VERSION_CONFLICT",
……@@ -2613,11 +2603,6 @@
26132603 "newVersion": "2.6.1",
26142604 "newTree": "6d6f0aff7bfff8b3693ddd00349d7aa296cfa35adc9abb0865fba66828814db5",
26152605 "existing": [
2616 {
2617 "appName": "ap-bridge",
2618 "version": "2.5.3",
2619 "tree": "15e8b9d1cf2b5299e2d1ed51af82f65fe33c5d61c2662966716ede785ca56ca0"
2620 },
26212606 {
26222607 "appName": "atproto-bridge",
26232608 "version": "2.5.1",
……@@ -2657,10 +2642,15 @@
26572642 "appName": "favela-bridge",
26582643 "version": "2.5.1",
26592644 "tree": "e667c2001426484c7866c301cac3b85ebcdb0075aa815ba494dac1fc065a9d00"
2645 },
2646 {
2647 "appName": "blender-repo-sync",
2648 "version": "2.5.1",
2649 "tree": "e667c2001426484c7866c301cac3b85ebcdb0075aa815ba494dac1fc065a9d00"
26602650 }
26612651 ],
2662 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2663 "acceptedAt": "2026-09-08T14:50:30.040Z"
2652 "reason": "dep version-splits only; 0 code-differs",
2653 "acceptedAt": "2026-09-10T00:03:36.827Z"
26642654 },
26652655 {
26662656 "type": "VERSION_CONFLICT",
……@@ -2668,11 +2658,6 @@
26682658 "newVersion": "3.1.10",
26692659 "newTree": "e693499377f146eec5788fa2887c4e42614f7f2efd3d5848d9019deec86c6632",
26702660 "existing": [
2671 {
2672 "appName": "ap-bridge",
2673 "version": "3.1.7",
2674 "tree": "7533d63c3ba5834ba72ae7284df9b93f476b7ae190b31c6b74f1a32c784bb587"
2675 },
26762661 {
26772662 "appName": "atproto-bridge",
26782663 "version": "3.1.7",
……@@ -2712,10 +2697,15 @@
27122697 "appName": "favela-bridge",
27132698 "version": "3.1.7",
27142699 "tree": "7533d63c3ba5834ba72ae7284df9b93f476b7ae190b31c6b74f1a32c784bb587"
2700 },
2701 {
2702 "appName": "blender-repo-sync",
2703 "version": "3.1.7",
2704 "tree": "7533d63c3ba5834ba72ae7284df9b93f476b7ae190b31c6b74f1a32c784bb587"
27152705 }
27162706 ],
2717 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2718 "acceptedAt": "2026-09-08T14:50:30.040Z"
2707 "reason": "dep version-splits only; 0 code-differs",
2708 "acceptedAt": "2026-09-10T00:03:36.827Z"
27192709 },
27202710 {
27212711 "type": "VERSION_CONFLICT",
……@@ -2723,11 +2713,6 @@
27232713 "newVersion": "5.2.1",
27242714 "newTree": "d99fbe108f5700f5e73d908e2d3d39ed44021b11bc74e1f152ebb493719b9eaa",
27252715 "existing": [
2726 {
2727 "appName": "ap-bridge",
2728 "version": "5.1.2",
2729 "tree": "64acc06cc1a667239638e61bf22495a5e6e7732f929725dde1727a3bb606b452"
2730 },
27312716 {
27322717 "appName": "atproto-bridge",
27332718 "version": "5.1.2",
……@@ -2774,8 +2759,8 @@
27742759 "tree": "f4b7868f220d0f43a5749ae1f8ec48107815042073364c775c5e79cc1ede412a"
27752760 }
27762761 ],
2777 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2778 "acceptedAt": "2026-09-08T14:50:30.040Z"
2762 "reason": "dep version-splits only; 0 code-differs",
2763 "acceptedAt": "2026-09-10T00:03:36.827Z"
27792764 },
27802765 {
27812766 "type": "VERSION_CONFLICT",
……@@ -2783,11 +2768,6 @@
27832768 "newVersion": "1.1.1",
27842769 "newTree": "4664a97e951dbbfc25e868cbdbec870de2682812c1c19fe7f6d3daf2fe33446a",
27852770 "existing": [
2786 {
2787 "appName": "ap-bridge",
2788 "version": "1.1.0",
2789 "tree": "a347c714d89f7eb5bf2598f115961a901ccf931540ab64a48f9fffb516da6c9d"
2790 },
27912771 {
27922772 "appName": "atproto-bridge",
27932773 "version": "1.1.0",
……@@ -2834,8 +2814,8 @@
28342814 "tree": "a347c714d89f7eb5bf2598f115961a901ccf931540ab64a48f9fffb516da6c9d"
28352815 }
28362816 ],
2837 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2838 "acceptedAt": "2026-09-08T14:50:30.040Z"
2817 "reason": "dep version-splits only; 0 code-differs",
2818 "acceptedAt": "2026-09-10T00:03:36.827Z"
28392819 },
28402820 {
28412821 "type": "VERSION_CONFLICT",
……@@ -2843,11 +2823,6 @@
28432823 "newVersion": "0.1.6",
28442824 "newTree": "4db5ae5fc0ad8552270405cd87877ac18d796bf082a05cb55e03a158af622290",
28452825 "existing": [
2846 {
2847 "appName": "ap-bridge",
2848 "version": "0.1.4",
2849 "tree": "b799e6ba8726aa951b45f12cc7ecffe5f4e9ee1e8adf09a34d026d9d5658828a"
2850 },
28512826 {
28522827 "appName": "atproto-bridge",
28532828 "version": "0.1.4",
……@@ -2869,8 +2844,8 @@
28692844 "tree": "b799e6ba8726aa951b45f12cc7ecffe5f4e9ee1e8adf09a34d026d9d5658828a"
28702845 }
28712846 ],
2872 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2873 "acceptedAt": "2026-09-08T14:50:30.040Z"
2847 "reason": "dep version-splits only; 0 code-differs",
2848 "acceptedAt": "2026-09-10T00:03:36.827Z"
28742849 },
28752850 {
28762851 "type": "VERSION_CONFLICT",
……@@ -2919,8 +2894,8 @@
29192894 "tree": "91b555116e75b7bc6309063652b2de61264901fb1e9a0326886bf355acd0acd8"
29202895 }
29212896 ],
2922 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2923 "acceptedAt": "2026-09-08T14:50:30.040Z"
2897 "reason": "dep version-splits only; 0 code-differs",
2898 "acceptedAt": "2026-09-10T00:03:36.827Z"
29242899 },
29252900 {
29262901 "type": "VERSION_CONFLICT",
……@@ -2928,11 +2903,6 @@
29282903 "newVersion": "3.1.0",
29292904 "newTree": "9c22db1f4e3137df4e44ba33887b65ce280bfc93454f8b91d2e41b458452e86b",
29302905 "existing": [
2931 {
2932 "appName": "ap-bridge",
2933 "version": "3.0.0",
2934 "tree": "f0d148ddaf94d3cbef50e8f1d8ae3a761a317115a7fe520d8c34d06247eac086"
2935 },
29362906 {
29372907 "appName": "atproto-bridge",
29382908 "version": "3.0.0",
……@@ -2972,10 +2942,15 @@
29722942 "appName": "favela-bridge",
29732943 "version": "3.0.0",
29742944 "tree": "f0d148ddaf94d3cbef50e8f1d8ae3a761a317115a7fe520d8c34d06247eac086"
2945 },
2946 {
2947 "appName": "blender-repo-sync",
2948 "version": "3.0.0",
2949 "tree": "f0d148ddaf94d3cbef50e8f1d8ae3a761a317115a7fe520d8c34d06247eac086"
29752950 }
29762951 ],
2977 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
2978 "acceptedAt": "2026-09-08T14:50:30.040Z"
2952 "reason": "dep version-splits only; 0 code-differs",
2953 "acceptedAt": "2026-09-10T00:03:36.827Z"
29792954 },
29802955 {
29812956 "type": "VERSION_CONFLICT",
……@@ -3019,13 +2994,13 @@
30192994 "tree": "be43fb4daea0f826da2fdd4bc4ba71a7fd22a6a9ce60317721f8301fd21ce414"
30202995 },
30212996 {
3022 "appName": "favela-bridge",
3023 "version": "4.0.2",
3024 "tree": "027801001ac7f56c3fa5880ab3bea6d5ea9e44f805c52a5488c677b4dc4e0782"
2997 "appName": "blender-repo-sync",
2998 "version": "3.19.1",
2999 "tree": "be43fb4daea0f826da2fdd4bc4ba71a7fd22a6a9ce60317721f8301fd21ce414"
30253000 }
30263001 ],
3027 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3028 "acceptedAt": "2026-09-08T14:50:30.040Z"
3002 "reason": "dep version-splits only; 0 code-differs",
3003 "acceptedAt": "2026-09-10T00:03:36.827Z"
30293004 },
30303005 {
30313006 "type": "VERSION_CONFLICT",
……@@ -3072,40 +3047,30 @@
30723047 "appName": "hyperident",
30733048 "version": "3.3.0",
30743049 "tree": "754944ca8ff184c8bdc55a8db26d1c1fcaf8f0fa855fd6779b3eb8c3ca3ec9e4"
3075 },
3076 {
3077 "appName": "favela-bridge",
3078 "version": "3.3.0",
3079 "tree": "754944ca8ff184c8bdc55a8db26d1c1fcaf8f0fa855fd6779b3eb8c3ca3ec9e4"
30803050 }
30813051 ],
3082 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3083 "acceptedAt": "2026-09-08T14:50:30.040Z"
3052 "reason": "dep version-splits only; 0 code-differs",
3053 "acceptedAt": "2026-09-10T00:03:36.827Z"
30843054 },
30853055 {
30863056 "type": "VERSION_CONFLICT",
30873057 "dep": "favela-markdown",
3088 "newVersion": "0.1.6",
3089 "newTree": "97d64cb2674377910d3ec28f3f4246d7e3fbc1b9b06b8b9d1ef6360cc0765569",
3058 "newVersion": "0.2.0",
3059 "newTree": "e980c91c65708beb2d24964f4f8bce19d01f9783d1d93e4eff8674851df64611",
30903060 "existing": [
30913061 {
30923062 "appName": "ap-bridge",
3093 "version": "0.1.4",
3094 "tree": "e303eceac5fcb441423d31d16fd57d096491c8133d7b3b09d5979817a831e39a"
3095 },
3096 {
3097 "appName": "favela-peer",
3098 "version": "0.1.4",
3099 "tree": "e303eceac5fcb441423d31d16fd57d096491c8133d7b3b09d5979817a831e39a"
3063 "version": "0.1.6",
3064 "tree": "08913adf8bf7452a12cc06528c49b4629c880de61fa45f01990e33b000a820d9"
31003065 },
31013066 {
31023067 "appName": "favela-bridge",
3103 "version": "0.1.4",
3104 "tree": "e303eceac5fcb441423d31d16fd57d096491c8133d7b3b09d5979817a831e39a"
3068 "version": "0.1.6",
3069 "tree": "08913adf8bf7452a12cc06528c49b4629c880de61fa45f01990e33b000a820d9"
31053070 }
31063071 ],
3107 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3108 "acceptedAt": "2026-09-08T14:50:30.040Z"
3072 "reason": "dep version-splits only; 0 code-differs",
3073 "acceptedAt": "2026-09-10T00:03:36.827Z"
31093074 },
31103075 {
31113076 "type": "VERSION_CONFLICT",
……@@ -3154,8 +3119,8 @@
31543119 "tree": "154d2ec275e27ac7dd12861553c92bbeb72fc2964cf49eaaf90f560dde370f65"
31553120 }
31563121 ],
3157 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3158 "acceptedAt": "2026-09-08T14:50:30.040Z"
3122 "reason": "dep version-splits only; 0 code-differs",
3123 "acceptedAt": "2026-09-10T00:03:36.827Z"
31593124 },
31603125 {
31613126 "type": "VERSION_CONFLICT",
……@@ -3163,11 +3128,6 @@
31633128 "newVersion": "1.0.6",
31643129 "newTree": "d7176ab113d79ab81c4a811285dcaca3948b5c822aac38968594d55904c0f243",
31653130 "existing": [
3166 {
3167 "appName": "ap-bridge",
3168 "version": "1.0.5",
3169 "tree": "ccc9f7a97b5b543dd71ad0d76cd754752f6621c247a51d0ccb5fa0205597096a"
3170 },
31713131 {
31723132 "appName": "atproto-bridge",
31733133 "version": "1.0.3",
……@@ -3207,10 +3167,15 @@
32073167 "appName": "favela-bridge",
32083168 "version": "1.0.3",
32093169 "tree": "fc3e31bf44b915125dac844920370081192a04d04fb3902734573f91ecaaeebd"
3170 },
3171 {
3172 "appName": "blender-repo-sync",
3173 "version": "1.0.3",
3174 "tree": "fc3e31bf44b915125dac844920370081192a04d04fb3902734573f91ecaaeebd"
32103175 }
32113176 ],
3212 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3213 "acceptedAt": "2026-09-08T14:50:30.040Z"
3177 "reason": "dep version-splits only; 0 code-differs",
3178 "acceptedAt": "2026-09-10T00:03:36.827Z"
32143179 },
32153180 {
32163181 "type": "VERSION_CONFLICT",
……@@ -3218,11 +3183,6 @@
32183183 "newVersion": "1.13.0",
32193184 "newTree": "4d8d5a7eb968560e887d7c9d097a5326b281b67b04e69a5e6b34514985e861ae",
32203185 "existing": [
3221 {
3222 "appName": "ap-bridge",
3223 "version": "1.10.2",
3224 "tree": "c0897d0bcb7cceaa3e6aecb9504632a06685eec8329aa6ab92fed66f8c4b1110"
3225 },
32263186 {
32273187 "appName": "atproto-bridge",
32283188 "version": "1.10.1",
……@@ -3262,10 +3222,15 @@
32623222 "appName": "favela-bridge",
32633223 "version": "1.10.1",
32643224 "tree": "c4467b71d0ee8842122b76ba6b3447849bbded3364e74b7fc3517d0a89322a3a"
3225 },
3226 {
3227 "appName": "blender-repo-sync",
3228 "version": "1.10.1",
3229 "tree": "c4467b71d0ee8842122b76ba6b3447849bbded3364e74b7fc3517d0a89322a3a"
32653230 }
32663231 ],
3267 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3268 "acceptedAt": "2026-09-08T14:50:30.040Z"
3232 "reason": "dep version-splits only; 0 code-differs",
3233 "acceptedAt": "2026-09-10T00:03:36.827Z"
32693234 },
32703235 {
32713236 "type": "VERSION_CONFLICT",
……@@ -3273,11 +3238,6 @@
32733238 "newVersion": "4.0.7",
32743239 "newTree": "7236258ca920c2f9853c24ead4286ec92a5f709fdf0117f38257e9702752d3ce",
32753240 "existing": [
3276 {
3277 "appName": "ap-bridge",
3278 "version": "4.0.5",
3279 "tree": "d84eb36adf98ba4a7d62157d04e3775edb4fef0e031138e449a70e5a3e18c8e3"
3280 },
32813241 {
32823242 "appName": "atproto-bridge",
32833243 "version": "4.0.5",
……@@ -3317,10 +3277,15 @@
33173277 "appName": "favela-bridge",
33183278 "version": "4.0.5",
33193279 "tree": "d84eb36adf98ba4a7d62157d04e3775edb4fef0e031138e449a70e5a3e18c8e3"
3280 },
3281 {
3282 "appName": "blender-repo-sync",
3283 "version": "4.0.4",
3284 "tree": "c1df9d82fc790e490c5bcca572b7b7934f359bc3e902eef663b21f5cc0112412"
33203285 }
33213286 ],
3322 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3323 "acceptedAt": "2026-09-08T14:50:30.040Z"
3287 "reason": "dep version-splits only; 0 code-differs",
3288 "acceptedAt": "2026-09-10T00:03:36.827Z"
33243289 },
33253290 {
33263291 "type": "VERSION_CONFLICT",
……@@ -3334,8 +3299,8 @@
33343299 "tree": "cbdbdac48d924a942ee4568fcc7631961423841a6fb3be3769025093334ad8cf"
33353300 }
33363301 ],
3337 "reason": "version-splits only: dry-run reports 0 code-differs, 0 unclassified",
3338 "acceptedAt": "2026-09-08T14:50:30.040Z"
3302 "reason": "dep version-splits only; 0 code-differs",
3303 "acceptedAt": "2026-09-10T00:03:36.827Z"
33393304 }
33403305 ]
33413306}
lib/pages.js +47 -1
……@@ -1989,8 +1989,18 @@ export function didSettings (did, reach = null) {
19891989 '<p class="who">Nothing is sent to Bluesky until you also switch the network on above.</p>'
19901990
19911991 if (did.submitted) {
1992 // ⛔ PUBLISHED IS NOT REACHABLE, and conflating them is why this looked finished when it was not.
1993 // A mint is P2P-only: the genesis carries `alsoKnownAs: []` and `services: {}`, so a published
1994 // DID has no server for Bluesky to fetch a repo from and resolves for nobody. A bridge grants the
1995 // handle and the endpoint, and the peer puts them on-chain.
1996 const carried = did.handle
1997 ? '<p>Reachable as <code>' + esc(did.handle) + '</code>' +
1998 (did.pdsUrl ? ' <span class="who">via ' + esc(did.pdsUrl) + '</span>' : '') + '</p>'
1999 : '<p class="warn">Published, but nothing can resolve it yet: this identity names no handle and ' +
2000 'no server. Ask a bridge to carry it.</p>' +
2001 '<p><a href="/did/carry">Get carried by a bridge</a></p>'
19922002 return '<h2>Bluesky identity</h2>' +
1993 '<p>Published as <code>' + esc(did.did) + '</code></p>' + vault + designate
2003 '<p>Published as <code>' + esc(did.did) + '</code></p>' + carried + vault + designate
19942004 }
19952005
19962006 return '<h2>Bluesky identity</h2>' +
……@@ -2145,3 +2155,39 @@ export function bridgeRelease (name, message = null) {
21452155 '<form method="post" action="/bridge/release"><button>give it up</button></form>' +
21462156 '<p><a href="/settings">keep it</a></p>')
21472157}
2158
2159/**
2160 * Ask a bridge to carry this identity — and put what it grants on-chain.
2161 *
2162 * ⛔ ONE SCREEN FOR ONE DECISION. The two halves are useless apart: a bridge carrying a DID that
2163 * resolves nowhere, or a handle published permanently against a server that has never heard of you.
2164 *
2165 * ⛔ AND IT SAYS WHAT IS PERMANENT. The bridge can drop you; the PLC append cannot be undone. Those
2166 * are different kinds of commitment and a person should meet the difference before the button.
2167 */
2168export function didCarry (did, message = null) {
2169 const warn = message ? '<p class="warn">' + esc(message) + '</p>' : ''
2170 return layout('get carried', warn +
2171 '<h1>Ask a bridge to carry this identity</h1>' +
2172 '<p><code>' + esc(did) + '</code></p>' +
2173 '<p>A bridge serves your signed records to Bluesky. It holds no key for you — it fetches what ' +
2174 'this device signed and re-serves it — so this asks for reach, not for authority.</p>' +
2175 '<form method="post" action="/did/carry">' +
2176 '<p><label>Bridge key<br><input type="text" name="bridge" placeholder="64 hex characters" ' +
2177 'autocomplete="off"></label></p>' +
2178 '<p class="who">The bridge prints this when it starts.</p>' +
2179 '<p><label>Name you want<br><input type="text" name="name" placeholder="alice" ' +
2180 'autocomplete="off"></label></p>' +
2181 '<p class="who">The bridge grants the full handle under its own domain — it owns that namespace, ' +
2182 'so it is the only thing that can answer for the name.</p>' +
2183 '<p><label>Recovery passphrase<br><input type="password" name="passphrase" ' +
2184 'autocomplete="current-password"></label></p>' +
2185 '<p class="who">Needed once. Changing where an identity lives is signed by its recovery key, not ' +
2186 'by the key this device posts with — which is exactly why losing a device does not lose the ' +
2187 'identity.</p>' +
2188 '<p class="warn">⛔ The second half of this is permanent. Recording the handle and the server on ' +
2189 'your identity is an append to a global public log: it cannot be undone or edited, and the old ' +
2190 'state stays readable for ever. The bridge itself can let you go; this cannot.</p>' +
2191 '<button>ask, and publish</button></form>' +
2192 '<p><a href="/settings">cancel</a></p>')
2193}
lib/router.js +33 -0
……@@ -960,6 +960,39 @@ export async function route (req, res, ctx) {
960960 'Bluesky posts will be published under ' + st.did))
961961 }
962962
963 // ⛔ GETTING CARRIED — the step that makes a published DID resolvable at all. A mint is P2P-only,
964 // so the genesis names no handle and no server; until a bridge grants both and the peer puts them
965 // on-chain, Bluesky has nothing to fetch and the identity resolves for nobody.
966 if (req.method === 'GET' && path === '/did/carry') {
967 const st = await client.call('did-status').catch(() => null)
968 if (!st || !st.did) return seeOther(res, '/settings')
969 if (st.handle) return seeOther(res, '/settings?m=' + encodeURIComponent('a bridge already carries this identity'))
970 return send(res, pages.didCarry(st.did, url.searchParams.get('m')))
971 }
972
973 if (req.method === 'POST' && path === '/did/carry') {
974 const form = await body(req)
975 const bridge = String(form.bridge || '').trim()
976 const name = String(form.name || '').trim()
977 const passphrase = String(form.passphrase || '')
978 if (!bridge || !name || !passphrase) {
979 return seeOther(res, '/did/carry?m=' + encodeURIComponent('a bridge key, a name and your passphrase are all needed'))
980 }
981 try {
982 // ⛔ ONE CALL. The daemon does both halves in the right order — reversible first — so a refusal
983 // from the bridge never leaves a permanent append behind it.
984 const r = await client.call('did-carry', { bridge, name, passphrase })
985 return seeOther(res, '/settings?m=' + encodeURIComponent(
986 r.pending
987 ? 'published as ' + r.handle + ', but the bridge is not serving it yet'
988 : 'published as ' + r.handle))
989 } catch (err) {
990 // Verbatim: the daemon knows whether the name was taken, the passphrase was wrong, or the
991 // directory refused the operation — and those need different actions.
992 return seeOther(res, '/did/carry?m=' + encodeURIComponent(err.message))
993 }
994 }
995
963996 if (req.method === 'GET' && path === '/did/publish') {
964997 const st = await client.call('did-status').catch(() => null)
965998 if (!st || !st.did) return seeOther(res, '/settings')
test/routes.test.js +59 -0
……@@ -1588,6 +1588,65 @@ test('★ POST /bridge/release uses the remembered bridge, and clears the name',
15881588 t.is(calls.find((c) => c.cmd === 'set-reach').args.fediverse, null, 'and the name is cleared')
15891589})
15901590
1591// ⛔ PUBLISHED IS NOT REACHABLE. A mint is P2P-only — the genesis names no handle and no server — so
1592// a DID can be published to the global directory and resolve for nobody. These pin that the page says
1593// so, and that the irreversible half is never reached by a GET.
1594test('★ a published DID with no handle says it resolves for nobody, and offers the fix', async (t) => {
1595 answers.whoami = { feed: 'ab', device: 'cd', linked: true }
1596 answers.profile = { name: 'x' }; answers.profiles = {}; answers.namespace = null
1597 answers['did-status'] = { did: 'did:plc:abc', sealed: true, submitted: true, publishable: true, handle: null }
1598 const r = await request('GET', '/settings', { headers: { cookie } })
1599 t.ok(/nothing can resolve it yet/.test(r.body), 'it does not call this finished')
1600 t.ok(r.body.includes('/did/carry'), 'and offers the step that fixes it')
1601})
1602
1603test('★ once carried, it reports the handle rather than offering again', async (t) => {
1604 answers.whoami = { feed: 'ab', device: 'cd', linked: true }
1605 answers.profile = { name: 'x' }; answers.profiles = {}; answers.namespace = null
1606 answers['did-status'] = { did: 'did:plc:abc', sealed: true, submitted: true, publishable: true, handle: 'alice.7rnx.net', pdsUrl: 'https://pds.7rnx.net' }
1607 const r = await request('GET', '/settings', { headers: { cookie } })
1608 t.ok(/Reachable as/.test(r.body))
1609 t.ok(r.body.includes('alice.7rnx.net'))
1610 t.absent(r.body.includes('/did/carry'), 'no second offer')
1611})
1612
1613test('⛔ GET /did/carry confirms, names what is permanent, and publishes NOTHING', async (t) => {
1614 answers.whoami = { feed: 'ab', device: 'cd', linked: true }
1615 answers['did-status'] = { did: 'did:plc:abc', sealed: true, submitted: true, publishable: true, handle: null }
1616 calls.length = 0
1617 const r = await request('GET', '/did/carry', { headers: { cookie } })
1618 t.is(r.status, 200)
1619 t.ok(/cannot be undone|permanent/i.test(r.body), 'it says which half is permanent')
1620 t.ok(/passphrase/i.test(r.body), 'and asks for the key that is allowed to change an identity')
1621 t.absent(calls.find((c) => c.cmd === 'did-carry'), 'a GET does nothing')
1622})
1623
1624test('★★ POST /did/carry does both halves in one call', async (t) => {
1625 answers.whoami = { feed: 'ab', device: 'cd', linked: true }
1626 answers['did-carry'] = { did: 'did:plc:abc', handle: 'alice.7rnx.net', adopted: true, pending: false }
1627 calls.length = 0
1628 const r = await request('POST', '/did/carry', {
1629 headers: { cookie, 'content-type': 'application/x-www-form-urlencoded' },
1630 body: 'bridge=' + 'b'.repeat(64) + '&name=alice&passphrase=hunter2hunter2'
1631 })
1632 t.is(r.status, 303)
1633 const c = calls.find((x) => x.cmd === 'did-carry')
1634 t.is(c.args.name, 'alice')
1635 t.is(c.args.passphrase, 'hunter2hunter2', 'the passphrase reaches the daemon, which holds the vault')
1636 t.ok(decodeURIComponent(r.headers.location || '').includes('alice.7rnx.net'), r.headers.location)
1637})
1638
1639test('⛔ a missing passphrase never reaches the daemon', async (t) => {
1640 answers.whoami = { feed: 'ab', device: 'cd', linked: true }
1641 calls.length = 0
1642 const r = await request('POST', '/did/carry', {
1643 headers: { cookie, 'content-type': 'application/x-www-form-urlencoded' },
1644 body: 'bridge=' + 'b'.repeat(64) + '&name=alice'
1645 })
1646 t.is(r.status, 303)
1647 t.absent(calls.find((x) => x.cmd === 'did-carry'), 'nothing permanent was attempted')
1648})
1649
15911650test('shut down', async (t) => {
15921651 await new Promise((r) => server.close(r))
15931652 await new Promise((r) => daemon.close(r))