OverviewFilesCommitsIssuesDocsReleasesPeers

ap-bridge commits / 49cb00e

0.10.8: handles are links, so the combined page can be navigated
0.10.7 put every peer on one page and left the handles as plain text, so reading one account still meant knowing its URL — the same as the pages not being there. A handle on THIS host now goes to that peer's own timeline; anyone else's goes to their own server, marked nofollow noopener ugc because we did not author it. ⛔ THE HOST HALF IS COMPARED WHOLE, splitting on the LAST '@' — a handle is `@name@host` and the name cannot contain one. `@ap.7rnx.net@evil.example` is not us, and rewriting it into a local path would put a stranger behind one of our pages. Asserted. 1216/1216 pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
49cb00e985e0c42156bd5d1fcdd77d6ea451a976
by plankatron <fleeky@gmail.com> · 2026-09-15T16:28:28.000Z

Changed files (4) +149 -96

.pgh-lock.json +93 -93
……@@ -1,9 +1,9 @@
11{
22 "name": "ap-bridge",
3 "version": "0.10.6",
3 "version": "0.10.7",
44 "runtime": "bare",
5 "rootTreeHash": "f29de4e2e53b8bd8a0eca9ed94aba91a52192f096d663d27e239e38ad7b79e6a",
6 "publishedAt": "2026-09-15T16:14:36.246Z",
5 "rootTreeHash": "38ee12c24f843a8bb57fee2d1821ea985935b37a015214c1632d35361b101aa7",
6 "publishedAt": "2026-09-15T16:24:17.618Z",
77 "deps": [
88 {
99 "name": "@hyperswarm/secret-stream",
……@@ -4004,8 +4004,8 @@
40044004 "tree": "38f44af48b2d59b46f1b5db31b81d02f3ca8b8bad6bc0fb9fffff698241f5e37"
40054005 }
40064006 ],
4007 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4008 "acceptedAt": "2026-09-15T16:14:36.263Z"
4007 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4008 "acceptedAt": "2026-09-15T16:24:17.637Z"
40094009 },
40104010 {
40114011 "type": "VERSION_CONFLICT",
……@@ -4019,8 +4019,8 @@
40194019 "tree": "ee91b6bd77101e3404ca571b2e5adf0f47029d174398a05f50294fc207e39d99"
40204020 }
40214021 ],
4022 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4023 "acceptedAt": "2026-09-15T16:14:36.263Z"
4022 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4023 "acceptedAt": "2026-09-15T16:24:17.637Z"
40244024 },
40254025 {
40264026 "type": "VERSION_CONFLICT",
……@@ -4034,8 +4034,8 @@
40344034 "tree": "3bb78d8f06263a549bd1077f37a7df257b1d557e44608631435af625f05a9c11"
40354035 }
40364036 ],
4037 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4038 "acceptedAt": "2026-09-15T16:14:36.263Z"
4037 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4038 "acceptedAt": "2026-09-15T16:24:17.637Z"
40394039 },
40404040 {
40414041 "type": "VERSION_CONFLICT",
……@@ -4054,8 +4054,8 @@
40544054 "tree": "58c0bf8698af19464d0ee8354a77ed1ac96d3a5fa18aa4e794686cfbbf080e5d"
40554055 }
40564056 ],
4057 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4058 "acceptedAt": "2026-09-15T16:14:36.263Z"
4057 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4058 "acceptedAt": "2026-09-15T16:24:17.637Z"
40594059 },
40604060 {
40614061 "type": "VERSION_CONFLICT",
……@@ -4069,8 +4069,8 @@
40694069 "tree": "da4c6b2654e9d66f10b0faa989311cf182878c24ab51b1c41458cfbf37ad29cd"
40704070 }
40714071 ],
4072 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4073 "acceptedAt": "2026-09-15T16:14:36.263Z"
4072 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4073 "acceptedAt": "2026-09-15T16:24:17.637Z"
40744074 },
40754075 {
40764076 "type": "VERSION_CONFLICT",
……@@ -4084,8 +4084,8 @@
40844084 "tree": "40be8f559a13b54ebf0689e63e6c70f0d218035359e17c497ed7bc8a85c3cc95"
40854085 }
40864086 ],
4087 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4088 "acceptedAt": "2026-09-15T16:14:36.263Z"
4087 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4088 "acceptedAt": "2026-09-15T16:24:17.637Z"
40894089 },
40904090 {
40914091 "type": "VERSION_CONFLICT",
……@@ -4099,8 +4099,8 @@
40994099 "tree": "3eae85efce82299769898c8151b5ed0a94e5a5ebdbcdee2105b815ca733a61cb"
41004100 }
41014101 ],
4102 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4103 "acceptedAt": "2026-09-15T16:14:36.263Z"
4102 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4103 "acceptedAt": "2026-09-15T16:24:17.637Z"
41044104 },
41054105 {
41064106 "type": "VERSION_CONFLICT",
……@@ -4114,8 +4114,8 @@
41144114 "tree": "8d9e01d443a127781773598d2e77c3f372334fad09e20623a819dabe49b22e1a"
41154115 }
41164116 ],
4117 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4118 "acceptedAt": "2026-09-15T16:14:36.263Z"
4117 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4118 "acceptedAt": "2026-09-15T16:24:17.637Z"
41194119 },
41204120 {
41214121 "type": "VERSION_CONFLICT",
……@@ -4129,8 +4129,8 @@
41294129 "tree": "dc1ad6c999fe90d946ba0ef34698ea9af451b639be2ad1c5b61eabb08337a6ca"
41304130 }
41314131 ],
4132 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4133 "acceptedAt": "2026-09-15T16:14:36.263Z"
4132 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4133 "acceptedAt": "2026-09-15T16:24:17.637Z"
41344134 },
41354135 {
41364136 "type": "VERSION_CONFLICT",
……@@ -4144,8 +4144,8 @@
41444144 "tree": "88b4779570e5113aa21b204989ac018d1628b387681f7e53428a7c99114fb701"
41454145 }
41464146 ],
4147 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4148 "acceptedAt": "2026-09-15T16:14:36.263Z"
4147 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4148 "acceptedAt": "2026-09-15T16:24:17.637Z"
41494149 },
41504150 {
41514151 "type": "VERSION_CONFLICT",
……@@ -4159,8 +4159,8 @@
41594159 "tree": "720b867ec4300a3caa2325eb1449499f9940bfb88341ecceb5992fa0fdf5f37d"
41604160 }
41614161 ],
4162 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4163 "acceptedAt": "2026-09-15T16:14:36.263Z"
4162 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4163 "acceptedAt": "2026-09-15T16:24:17.637Z"
41644164 },
41654165 {
41664166 "type": "VERSION_CONFLICT",
……@@ -4174,8 +4174,8 @@
41744174 "tree": "b697fe174482a708b49d0764cd4786291845f0034a31e0699381ca7e7b269d04"
41754175 }
41764176 ],
4177 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4178 "acceptedAt": "2026-09-15T16:14:36.263Z"
4177 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4178 "acceptedAt": "2026-09-15T16:24:17.637Z"
41794179 },
41804180 {
41814181 "type": "VERSION_CONFLICT",
……@@ -4189,8 +4189,8 @@
41894189 "tree": "767f07242277ae80bd395de5a4969fcdbf956c216158ae517fb2b562558ac1a4"
41904190 }
41914191 ],
4192 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4193 "acceptedAt": "2026-09-15T16:14:36.263Z"
4192 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4193 "acceptedAt": "2026-09-15T16:24:17.637Z"
41944194 },
41954195 {
41964196 "type": "VERSION_CONFLICT",
……@@ -4204,8 +4204,8 @@
42044204 "tree": "de7deed21f587ffc8bde4971abe00fca77bb6c71c4e7effb31ad34ee330815df"
42054205 }
42064206 ],
4207 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4208 "acceptedAt": "2026-09-15T16:14:36.263Z"
4207 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4208 "acceptedAt": "2026-09-15T16:24:17.637Z"
42094209 },
42104210 {
42114211 "type": "VERSION_CONFLICT",
……@@ -4219,8 +4219,8 @@
42194219 "tree": "2df42517ebf73cd9c11f2f652f75e87401fd4ed7b856c0adc15c33baf1d4f1ad"
42204220 }
42214221 ],
4222 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4223 "acceptedAt": "2026-09-15T16:14:36.263Z"
4222 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4223 "acceptedAt": "2026-09-15T16:24:17.637Z"
42244224 },
42254225 {
42264226 "type": "VERSION_CONFLICT",
……@@ -4234,8 +4234,8 @@
42344234 "tree": "325aca171cbff560487177584078c8066133e91176639ca47c98d70e195aa92e"
42354235 }
42364236 ],
4237 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4238 "acceptedAt": "2026-09-15T16:14:36.263Z"
4237 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4238 "acceptedAt": "2026-09-15T16:24:17.637Z"
42394239 },
42404240 {
42414241 "type": "VERSION_CONFLICT",
……@@ -4264,8 +4264,8 @@
42644264 "tree": "89a40400106bf4fef95fb5c44a66ee29aada6f76c7740bfba09d8aeeb841f39c"
42654265 }
42664266 ],
4267 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4268 "acceptedAt": "2026-09-15T16:14:36.263Z"
4267 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4268 "acceptedAt": "2026-09-15T16:24:17.637Z"
42694269 },
42704270 {
42714271 "type": "VERSION_CONFLICT",
……@@ -4279,8 +4279,8 @@
42794279 "tree": "1bd0eb382789c62cd4622d47bffb60984fdd766260c79f73a2fc7a136f3edbe9"
42804280 }
42814281 ],
4282 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4283 "acceptedAt": "2026-09-15T16:14:36.263Z"
4282 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4283 "acceptedAt": "2026-09-15T16:24:17.637Z"
42844284 },
42854285 {
42864286 "type": "VERSION_CONFLICT",
……@@ -4294,8 +4294,8 @@
42944294 "tree": "4526fe9dc5468264c7171ec16e9303726674b7b44ca0b3e09cb8b9a6a1be6169"
42954295 }
42964296 ],
4297 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4298 "acceptedAt": "2026-09-15T16:14:36.263Z"
4297 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4298 "acceptedAt": "2026-09-15T16:24:17.637Z"
42994299 },
43004300 {
43014301 "type": "VERSION_CONFLICT",
……@@ -4309,8 +4309,8 @@
43094309 "tree": "32b291cd756e142da18a6ed01c351e024fcedc3e2b1ecfbfb85f3106ada4419b"
43104310 }
43114311 ],
4312 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4313 "acceptedAt": "2026-09-15T16:14:36.263Z"
4312 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4313 "acceptedAt": "2026-09-15T16:24:17.637Z"
43144314 },
43154315 {
43164316 "type": "VERSION_CONFLICT",
……@@ -4324,8 +4324,8 @@
43244324 "tree": "4a8cd3b0093092b33088617dc0415e8179882d7f2f13b7649962ca20b08beeed"
43254325 }
43264326 ],
4327 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4328 "acceptedAt": "2026-09-15T16:14:36.263Z"
4327 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4328 "acceptedAt": "2026-09-15T16:24:17.637Z"
43294329 },
43304330 {
43314331 "type": "VERSION_CONFLICT",
……@@ -4339,8 +4339,8 @@
43394339 "tree": "4f63f165ee6a581f689b40c4a40df4df01ab6fba17d46bd29e40ef5bbdd9884f"
43404340 }
43414341 ],
4342 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4343 "acceptedAt": "2026-09-15T16:14:36.263Z"
4342 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4343 "acceptedAt": "2026-09-15T16:24:17.637Z"
43444344 },
43454345 {
43464346 "type": "VERSION_CONFLICT",
……@@ -4354,8 +4354,8 @@
43544354 "tree": "735109c736c0bd3413ab47414fd8b6ea9a99c401fe8e6d608459c79293806754"
43554355 }
43564356 ],
4357 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4358 "acceptedAt": "2026-09-15T16:14:36.263Z"
4357 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4358 "acceptedAt": "2026-09-15T16:24:17.637Z"
43594359 },
43604360 {
43614361 "type": "VERSION_CONFLICT",
……@@ -4369,8 +4369,8 @@
43694369 "tree": "b32b75bf1b2acdd18ed0cc370d01d477fba42ba09fd1f2f78af3ebad925e72d5"
43704370 }
43714371 ],
4372 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4373 "acceptedAt": "2026-09-15T16:14:36.263Z"
4372 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4373 "acceptedAt": "2026-09-15T16:24:17.637Z"
43744374 },
43754375 {
43764376 "type": "VERSION_CONFLICT",
……@@ -4389,8 +4389,8 @@
43894389 "tree": "189397178121e9a18430943345dab820691648a324229071ceb980bbb77a7393"
43904390 }
43914391 ],
4392 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4393 "acceptedAt": "2026-09-15T16:14:36.263Z"
4392 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4393 "acceptedAt": "2026-09-15T16:24:17.637Z"
43944394 },
43954395 {
43964396 "type": "VERSION_CONFLICT",
……@@ -4404,8 +4404,8 @@
44044404 "tree": "3bedca5287a9041fc2fd5ec5ace4df1fa86240e6afec0a105ba67398bafc09a5"
44054405 }
44064406 ],
4407 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4408 "acceptedAt": "2026-09-15T16:14:36.263Z"
4407 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4408 "acceptedAt": "2026-09-15T16:24:17.637Z"
44094409 },
44104410 {
44114411 "type": "VERSION_CONFLICT",
……@@ -4419,8 +4419,8 @@
44194419 "tree": "b9ca9b272008bd67672a1b252390e8b527095c46b46cf6b6725a7a187eb038b6"
44204420 }
44214421 ],
4422 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4423 "acceptedAt": "2026-09-15T16:14:36.263Z"
4422 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4423 "acceptedAt": "2026-09-15T16:24:17.637Z"
44244424 },
44254425 {
44264426 "type": "VERSION_CONFLICT",
……@@ -4434,8 +4434,8 @@
44344434 "tree": "7793645d7d4248d6d6533e3cbcd4bf40bed4f38c678b0ca0606c15640ba5e7b9"
44354435 }
44364436 ],
4437 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4438 "acceptedAt": "2026-09-15T16:14:36.263Z"
4437 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4438 "acceptedAt": "2026-09-15T16:24:17.637Z"
44394439 },
44404440 {
44414441 "type": "VERSION_CONFLICT",
……@@ -4449,8 +4449,8 @@
44494449 "tree": "79447513d4ac0357c8d60bdc7b81b3c5143d761b26700340cba266c4d1cb77b0"
44504450 }
44514451 ],
4452 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4453 "acceptedAt": "2026-09-15T16:14:36.263Z"
4452 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4453 "acceptedAt": "2026-09-15T16:24:17.637Z"
44544454 },
44554455 {
44564456 "type": "VERSION_CONFLICT",
……@@ -4464,8 +4464,8 @@
44644464 "tree": "279d4e0447eb79fd75816864ba7f41f2df03080c9da69ea4603fe2900c8d9e53"
44654465 }
44664466 ],
4467 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4468 "acceptedAt": "2026-09-15T16:14:36.263Z"
4467 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4468 "acceptedAt": "2026-09-15T16:24:17.637Z"
44694469 },
44704470 {
44714471 "type": "VERSION_CONFLICT",
……@@ -4479,8 +4479,8 @@
44794479 "tree": "ed4e0b480417610e195ff0b59e5b9a453abbf2db6d6ce72d7cd522269f835e9a"
44804480 }
44814481 ],
4482 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4483 "acceptedAt": "2026-09-15T16:14:36.263Z"
4482 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4483 "acceptedAt": "2026-09-15T16:24:17.637Z"
44844484 },
44854485 {
44864486 "type": "VERSION_CONFLICT",
……@@ -4499,8 +4499,8 @@
44994499 "tree": "a9e07d54e526c838dfe5e27df33936682aefb218f61a45b6c15289243999f648"
45004500 }
45014501 ],
4502 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4503 "acceptedAt": "2026-09-15T16:14:36.263Z"
4502 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4503 "acceptedAt": "2026-09-15T16:24:17.637Z"
45044504 },
45054505 {
45064506 "type": "VERSION_CONFLICT",
……@@ -4514,8 +4514,8 @@
45144514 "tree": "9d84c86441fe138b227c4fd01d1e948aa83bf8d13cfb1aa957838feea05fbb57"
45154515 }
45164516 ],
4517 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4518 "acceptedAt": "2026-09-15T16:14:36.263Z"
4517 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4518 "acceptedAt": "2026-09-15T16:24:17.637Z"
45194519 },
45204520 {
45214521 "type": "VERSION_CONFLICT",
……@@ -4529,8 +4529,8 @@
45294529 "tree": "4a3afbe2fc7a882e24454eb2e7e7cfe6816811ee5d73ae0f92e8b9ea9cfb8c78"
45304530 }
45314531 ],
4532 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4533 "acceptedAt": "2026-09-15T16:14:36.263Z"
4532 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4533 "acceptedAt": "2026-09-15T16:24:17.637Z"
45344534 },
45354535 {
45364536 "type": "VERSION_CONFLICT",
……@@ -4544,8 +4544,8 @@
45444544 "tree": "1e5c5810d8971a3c27fde7fb0e4d633dcabbe2cf98d8df86b473f8d67eead8b9"
45454545 }
45464546 ],
4547 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4548 "acceptedAt": "2026-09-15T16:14:36.263Z"
4547 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4548 "acceptedAt": "2026-09-15T16:24:17.637Z"
45494549 },
45504550 {
45514551 "type": "VERSION_CONFLICT",
……@@ -4559,8 +4559,8 @@
45594559 "tree": "e3478f50e85ba0ac288efed83e84c992483904897dc39ccf243d20a4ea25d972"
45604560 }
45614561 ],
4562 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4563 "acceptedAt": "2026-09-15T16:14:36.263Z"
4562 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4563 "acceptedAt": "2026-09-15T16:24:17.637Z"
45644564 },
45654565 {
45664566 "type": "VERSION_CONFLICT",
……@@ -4574,8 +4574,8 @@
45744574 "tree": "c05d8bf7eab5024ea98140f78c84d12fb494b4b7b10c7eedeb50b2be842fa519"
45754575 }
45764576 ],
4577 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4578 "acceptedAt": "2026-09-15T16:14:36.263Z"
4577 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4578 "acceptedAt": "2026-09-15T16:24:17.637Z"
45794579 },
45804580 {
45814581 "type": "VERSION_CONFLICT",
……@@ -4589,8 +4589,8 @@
45894589 "tree": "0697bb338bbcec517353cffcdb2345a8232b9b90cc627a549a306f0323576390"
45904590 }
45914591 ],
4592 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4593 "acceptedAt": "2026-09-15T16:14:36.263Z"
4592 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4593 "acceptedAt": "2026-09-15T16:24:17.637Z"
45944594 },
45954595 {
45964596 "type": "VERSION_CONFLICT",
……@@ -4604,8 +4604,8 @@
46044604 "tree": "a366a73e74f8d80f106465058083b62bb70b833c721047124e99c89880e5c706"
46054605 }
46064606 ],
4607 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4608 "acceptedAt": "2026-09-15T16:14:36.263Z"
4607 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4608 "acceptedAt": "2026-09-15T16:24:17.637Z"
46094609 },
46104610 {
46114611 "type": "VERSION_CONFLICT",
……@@ -4619,8 +4619,8 @@
46194619 "tree": "7912e790c9e87e9829a6daa037c5f5da0cc4355214f51d334f96e57678dfddeb"
46204620 }
46214621 ],
4622 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4623 "acceptedAt": "2026-09-15T16:14:36.263Z"
4622 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4623 "acceptedAt": "2026-09-15T16:24:17.637Z"
46244624 },
46254625 {
46264626 "type": "VERSION_CONFLICT",
……@@ -4634,8 +4634,8 @@
46344634 "tree": "003ac841449fcdda1abc3c87fee291a5d9596d245925a7298bd8ef5f8e423eae"
46354635 }
46364636 ],
4637 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4638 "acceptedAt": "2026-09-15T16:14:36.263Z"
4637 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4638 "acceptedAt": "2026-09-15T16:24:17.637Z"
46394639 },
46404640 {
46414641 "type": "VERSION_CONFLICT",
……@@ -4654,8 +4654,8 @@
46544654 "tree": "7b3f314cf92558edbc90295c573885276a6add925318998c829c03d335edc765"
46554655 }
46564656 ],
4657 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4658 "acceptedAt": "2026-09-15T16:14:36.263Z"
4657 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4658 "acceptedAt": "2026-09-15T16:24:17.637Z"
46594659 },
46604660 {
46614661 "type": "VERSION_CONFLICT",
……@@ -4669,8 +4669,8 @@
46694669 "tree": "c486fe73805bf013e9c5de91b5780d1aa5d2b2295306f411f7863757aaa05e60"
46704670 }
46714671 ],
4672 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4673 "acceptedAt": "2026-09-15T16:14:36.263Z"
4672 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4673 "acceptedAt": "2026-09-15T16:24:17.637Z"
46744674 },
46754675 {
46764676 "type": "VERSION_CONFLICT",
……@@ -4684,8 +4684,8 @@
46844684 "tree": "10193a86e2c6f80c2d4377379a0aae4a959f8a40fd9e852b85fee081bfe6675a"
46854685 }
46864686 ],
4687 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4688 "acceptedAt": "2026-09-15T16:14:36.263Z"
4687 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4688 "acceptedAt": "2026-09-15T16:24:17.637Z"
46894689 },
46904690 {
46914691 "type": "VERSION_CONFLICT",
……@@ -4699,8 +4699,8 @@
46994699 "tree": "20b1ecd2937f3e35102892288234b86a8ec6deb3711016d96ff3509474ac465b"
47004700 }
47014701 ],
4702 "reason": "0.10.6: same 45 version-splits/docs/packaging, 0 code-differs",
4703 "acceptedAt": "2026-09-15T16:14:36.263Z"
4702 "reason": "0.10.7: same 45 version-splits/docs/packaging, 0 code-differs",
4703 "acceptedAt": "2026-09-15T16:24:17.637Z"
47044704 }
47054705 ]
47064706}
lib/public-timeline.js +31 -2
……@@ -32,6 +32,7 @@ display:flex;align-items:center;justify-content:center;font-weight:700;font-size
3232.main{min-width:0;flex:1}
3333.head{display:flex;gap:6px;align-items:baseline;flex-wrap:wrap}
3434.name{font-weight:700}
35.head a{color:inherit;text-decoration:none}.head a:hover .name{text-decoration:underline}
3536.handle,.time{color:#536471;font-size:14px}
3637.verb{color:#536471;font-size:14px;margin:1px 0 0}
3738.body{margin:3px 0 0;white-space:pre-wrap;word-wrap:break-word}
……@@ -101,11 +102,39 @@ function renderAttachments (list, host) {
101102 }).join('') + '</div>'
102103}
103104
105// Where a handle goes.
106//
107// ⛔ A COMBINED PAGE WITH NO WAY INTO A PEER'S OWN IS HALF A FEATURE — you had to already know the
108// URL to read one account, which is the same as it not being there. A handle on THIS host goes to
109// that peer's page; anyone else's goes to their own server.
110//
111// ⚠ THE HOST HALF IS COMPARED WHOLE. `@ap.7rnx.net@evil.example` and a name that merely contains our
112// host are not us, and rewriting either into a local path would put a stranger behind one of our
113// pages. Split on the LAST '@' — a handle is `@name@host` and the name cannot contain one.
114function authorHref (a, host) {
115 const h = a && a.handle
116 if (typeof h === 'string' && host) {
117 const at = h.lastIndexOf('@')
118 if (at > 0) {
119 const name = h.slice(1, at)
120 const hostPart = h.slice(at + 1)
121 if (hostPart === host && /^[A-Za-z0-9_.-]+$/.test(name)) {
122 return { href: '/ap/users/' + encodeURIComponent(name) + '/timeline', local: true }
123 }
124 }
125 }
126 return a && a.url ? { href: a.url, local: false } : null
127}
128
104129function renderRow (r, host) {
105130 const a = r.author || {}
106131 const name = a.name || String(a.handle || '').replace(/^@/, '').split('@')[0] || 'someone'
107 const head = '<div class="head"><span class="name">' + esc(name) + '</span>' +
108 (a.handle ? '<span class="handle">' + esc(a.handle) + '</span>' : '') +
132 const href = authorHref(a, host)
133 const wrap = (inner) => href
134 ? '<a href="' + esc(href.href) + '"' + (href.local ? '' : ' rel="nofollow noopener ugc"') + '>' + inner + '</a>'
135 : inner
136 const head = '<div class="head">' + wrap('<span class="name">' + esc(name) + '</span>' +
137 (a.handle ? '<span class="handle">' + esc(a.handle) + '</span>' : '')) +
109138 (r.at ? '<span class="time">· ' + esc(when(r.at)) + '</span>' : '') +
110139 (r.source === 'fediverse' ? '<span class="pill">fediverse</span>' : '') + '</div>'
111140
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "ap-bridge",
3 "version": "0.10.7",
3 "version": "0.10.8",
44 "description": "ActivityPub membrane \u2014 a second projection of the self-custody atproto peer",
55 "type": "module",
66 "main": "index.js",
test/public-timeline.test.js +24 -0
……@@ -150,3 +150,27 @@ test('★★ the feed now shows a like that arrived', (t) => {
150150 t.is(rows.length, 1, 'the one measured on the live bridge would appear')
151151 t.is(rows[0].verb, 'liked your post')
152152})
153
154test('★★ a handle is a link — ours to their page here, a stranger\'s to their own server', (t) => {
155 const rows = buildFeed({
156 self: { handle: '@fleeky@ap.7rnx.net' },
157 notes: [{ id: 'https://ap.7rnx.net/ap/users/fleeky/objects/1', type: 'Note', content: '<p>mine</p>', published: '2026-09-15T09:00:00Z' }],
158 inbound: [{ id: 'r', type: 'Create', actor: 'https://m.example/users/alice', inReplyTo: 'https://ap.7rnx.net/ap/users/fleeky/objects/1', public: true, published: '2026-09-15T10:00:00Z', content: '<p>hi</p>' }]
159 })
160 const body = publicTimeline({ host: 'ap.7rnx.net', rows, total: 2 })
161 // ⛔ A COMBINED PAGE WITH NO WAY INTO A PEER'S OWN IS HALF A FEATURE. You had to already know the
162 // URL to read one account, which is the same as it not being there.
163 t.ok(/href="\/ap\/users\/fleeky\/timeline"/.test(body), 'ours goes to their page on this bridge')
164 t.ok(/href="https:\/\/m.example\/users\/alice"/.test(body), "a stranger's goes to their own server")
165 t.ok(/rel="nofollow noopener ugc"/.test(body), 'and a link we did not author is marked as such')
166})
167
168test('⛔ a handle on another host is never rewritten into a local path', (t) => {
169 const rows = buildFeed({
170 self: {},
171 inbound: [{ id: 'x', type: 'Like', actor: 'https://evil.example/users/ap.7rnx.net', objectId: 'https://ap.7rnx.net/ap/objects/1', public: true, published: 'z' }]
172 })
173 const body = publicTimeline({ host: 'ap.7rnx.net', rows, total: 1 })
174 t.absent(/href="\/ap\/users\/ap.7rnx.net\/timeline"/.test(body),
175 'a name that merely looks like ours does not get one of our pages')
176})