mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(pubsub): restore browser pure p2p publishing
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
.codegraph/
|
||||||
|
.firecrawl/
|
||||||
|
.playwright-cli/
|
||||||
|
build/
|
||||||
|
coverage/
|
||||||
|
release-assets/
|
||||||
+69
-47
@@ -1,5 +1,51 @@
|
|||||||
|
diff --git a/dist/browser/helia/helia-for-pkc.js b/dist/browser/helia/helia-for-pkc.js
|
||||||
|
index e6821667b0601ac56a850e989bfedf76c14796a2..1a2ae7ab9b0afc605c9b4dcddccf25ac02aa1337 100644
|
||||||
|
--- a/dist/browser/helia/helia-for-pkc.js
|
||||||
|
+++ b/dist/browser/helia/helia-for-pkc.js
|
||||||
|
@@ -145,6 +145,11 @@ export async function createLibp2pJsClientOrUseExistingOne(pkcOptions) {
|
||||||
|
warmupPromisesByTopic.set(topic, p);
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
+ const ignoreBestEffortPubsubWarmupError = (operation, topic, err, options) => {
|
||||||
|
+ if (options?.signal?.aborted)
|
||||||
|
+ throw err;
|
||||||
|
+ log.error(`Best-effort pubsub peer warmup failed before ${operation} on topic`, topic, err);
|
||||||
|
+ };
|
||||||
|
const throwIfHeliaIsStoppingOrStopped = () => {
|
||||||
|
if (helia.libp2p.status === "stopped" || helia.libp2p.status === "stopping")
|
||||||
|
throw new PKCError("ERR_HELIAS_STOPPING_OR_STOPPED", {
|
||||||
|
@@ -290,8 +295,13 @@ export async function createLibp2pJsClientOrUseExistingOne(pkcOptions) {
|
||||||
|
if (!wasAlreadySubscribed)
|
||||||
|
helia.libp2p.services.pubsub.subscribe(topic);
|
||||||
|
try {
|
||||||
|
- await warmupForTopic(topic, options);
|
||||||
|
- const res = await helia.libp2p.services.pubsub.publish(topic, data);
|
||||||
|
+ try {
|
||||||
|
+ await warmupForTopic(topic, options);
|
||||||
|
+ }
|
||||||
|
+ catch (err) {
|
||||||
|
+ ignoreBestEffortPubsubWarmupError("publish", topic, err, options);
|
||||||
|
+ }
|
||||||
|
+ const res = await helia.libp2p.services.pubsub.publish(topic, data, { allowPublishToZeroTopicPeers: true });
|
||||||
|
log("Published new data to pubsub topic (string, e.g. community address)", topic, "Direct gossipsub recipients (libp2p peer IDs, NOT signer/community addresses):", res.recipients.map((p) => p.toString()));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
@@ -314,7 +324,12 @@ export async function createLibp2pJsClientOrUseExistingOne(pkcOptions) {
|
||||||
|
// locally subscribed to).
|
||||||
|
const warmupPromise = warmupForTopic(topic, options);
|
||||||
|
helia.libp2p.services.pubsub.subscribe(topic);
|
||||||
|
- await warmupPromise;
|
||||||
|
+ try {
|
||||||
|
+ await warmupPromise;
|
||||||
|
+ }
|
||||||
|
+ catch (err) {
|
||||||
|
+ ignoreBestEffortPubsubWarmupError("subscribe", topic, err, options);
|
||||||
|
+ }
|
||||||
|
},
|
||||||
|
unsubscribe: async (topic, handler, options) => {
|
||||||
|
throwIfHeliaIsStoppingOrStopped();
|
||||||
diff --git a/dist/browser/publications/publication.js b/dist/browser/publications/publication.js
|
diff --git a/dist/browser/publications/publication.js b/dist/browser/publications/publication.js
|
||||||
index 5e17c02a39c2715c7ac932695fe90d5078bce405..339d299de85ba5d144e4608f9189c88f4ef42dc8 100644
|
index 5e17c02a39c2715c7ac932695fe90d5078bce405..2d43d996e2b3cdab759e89c296eb9ed8aae857db 100644
|
||||||
--- a/dist/browser/publications/publication.js
|
--- a/dist/browser/publications/publication.js
|
||||||
+++ b/dist/browser/publications/publication.js
|
+++ b/dist/browser/publications/publication.js
|
||||||
@@ -842,8 +842,14 @@ class Publication extends TypedEmitter {
|
@@ -842,8 +842,14 @@ class Publication extends TypedEmitter {
|
||||||
@@ -19,49 +65,25 @@ index 5e17c02a39c2715c7ac932695fe90d5078bce405..339d299de85ba5d144e4608f9189c88f
|
|||||||
pubsubTopic: this._communityPubsubTopicWithFallback(),
|
pubsubTopic: this._communityPubsubTopicWithFallback(),
|
||||||
providerHeliaContexts: this._libp2pJsClientHeliaContexts()
|
providerHeliaContexts: this._libp2pJsClientHeliaContexts()
|
||||||
});
|
});
|
||||||
diff --git a/dist/browser/helia/helia-for-pkc.js b/dist/browser/helia/helia-for-pkc.js
|
diff --git a/dist/browser/runtime/browser/libp2p-extra-transports.js b/dist/browser/runtime/browser/libp2p-extra-transports.js
|
||||||
index 3eca64dd532a19393c55ddf953dfd4ef207c65f8..683fed56722effc54b1b08e5b050e311ed174424 100644
|
index 1b7028978d1da8c3f78e9b4d18e790a3ad025e25..2b8eff3ce509cff57ac5be3d31b26b38a5301a52 100644
|
||||||
--- a/dist/browser/helia/helia-for-pkc.js
|
--- a/dist/browser/runtime/browser/libp2p-extra-transports.js
|
||||||
+++ b/dist/browser/helia/helia-for-pkc.js
|
+++ b/dist/browser/runtime/browser/libp2p-extra-transports.js
|
||||||
@@ -161,6 +161,11 @@ export async function createLibp2pJsClientOrUseExistingOne(pkcOptions) {
|
@@ -1,3 +1,4 @@
|
||||||
warmupPromisesByTopic.set(topic, p);
|
-const extraLibp2pTransports = [];
|
||||||
return p;
|
+import { webTransport } from "@libp2p/webtransport";
|
||||||
};
|
+const extraLibp2pTransports = typeof globalThis.WebTransport === "function" ? [webTransport()] : [];
|
||||||
+ const ignoreBestEffortPubsubWarmupError = (operation, topic, err, options) => {
|
export default extraLibp2pTransports;
|
||||||
+ if (options?.signal?.aborted)
|
//# sourceMappingURL=libp2p-extra-transports.js.map
|
||||||
+ throw err;
|
diff --git a/package.json b/package.json
|
||||||
+ log.error(`Best-effort pubsub peer warmup failed before ${operation} on topic`, topic, err);
|
index 2a44f27220191ee556a317bf25005b7fcbde6aaa..335ee82cc7e9850eb1bc036b2a481ae5a575eabd 100644
|
||||||
+ };
|
--- a/package.json
|
||||||
const throwIfHeliaIsStoppingOrStopped = () => {
|
+++ b/package.json
|
||||||
if (helia.libp2p.status === "stopped" || helia.libp2p.status === "stopping")
|
@@ -78,6 +78,7 @@
|
||||||
throw new PKCError("ERR_HELIAS_STOPPING_OR_STOPPED", {
|
"@libp2p/identify": "4.1.3",
|
||||||
@@ -299,8 +304,13 @@ export async function createLibp2pJsClientOrUseExistingOne(pkcOptions) {
|
"@libp2p/interface": "3.2.2",
|
||||||
if (!wasAlreadySubscribed)
|
"@libp2p/peer-id": "6.0.8",
|
||||||
helia.libp2p.services.pubsub.subscribe(topic);
|
+ "@libp2p/webtransport": "6.0.0",
|
||||||
try {
|
"@multiformats/multiaddr": "13.0.1",
|
||||||
- await warmupForTopic(topic, options);
|
"@noble/curves": "2.2.0",
|
||||||
- const res = await helia.libp2p.services.pubsub.publish(topic, data);
|
"@pkcprotocol/pkc-logger": "0.1.0",
|
||||||
+ try {
|
|
||||||
+ await warmupForTopic(topic, options);
|
|
||||||
+ }
|
|
||||||
+ catch (err) {
|
|
||||||
+ ignoreBestEffortPubsubWarmupError("publish", topic, err, options);
|
|
||||||
+ }
|
|
||||||
+ const res = await helia.libp2p.services.pubsub.publish(topic, data, { allowPublishToZeroTopicPeers: true });
|
|
||||||
log("Published new data to pubsub topic (string, e.g. community address)", topic, "Direct gossipsub recipients (libp2p peer IDs, NOT signer/community addresses):", res.recipients.map((p) => p.toString()));
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
@@ -323,7 +333,12 @@ export async function createLibp2pJsClientOrUseExistingOne(pkcOptions) {
|
|
||||||
// locally subscribed to).
|
|
||||||
const warmupPromise = warmupForTopic(topic, options);
|
|
||||||
helia.libp2p.services.pubsub.subscribe(topic);
|
|
||||||
- await warmupPromise;
|
|
||||||
+ try {
|
|
||||||
+ await warmupPromise;
|
|
||||||
+ }
|
|
||||||
+ catch (err) {
|
|
||||||
+ ignoreBestEffortPubsubWarmupError("subscribe", topic, err, options);
|
|
||||||
+ }
|
|
||||||
},
|
|
||||||
unsubscribe: async (topic, handler, options) => {
|
|
||||||
throwIfHeliaIsStoppingOrStopped();
|
|
||||||
@@ -5,3 +5,6 @@ packageExtensions:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@types/react": ">=18.0.0"
|
"@types/react": ">=18.0.0"
|
||||||
react: ">=17.0.1"
|
react: ">=17.0.1"
|
||||||
|
"@pkcprotocol/pkc-js@0.0.47":
|
||||||
|
dependencies:
|
||||||
|
"@libp2p/webtransport": "6.0.0"
|
||||||
|
|||||||
+1
-19
@@ -1,21 +1,3 @@
|
|||||||
## [0.9.3](https://github.com/bitsocialnet/5chan/compare/v0.9.2...v0.9.3) (2026-06-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **ci:** keep raw board tests side-effect free ([75dd7a8](https://github.com/bitsocialnet/5chan/commit/75dd7a84967cb3c99da37780fb31bb6a947d7d57))
|
|
||||||
* **pubsub:** avoid false browser p2p provider failures ([10015de](https://github.com/bitsocialnet/5chan/commit/10015de6b925595694ce1abae547e628b169bf35))
|
|
||||||
* **release:** align blotter and release copy with LaTeX in /sci/ ([3577673](https://github.com/bitsocialnet/5chan/commit/35776737f2479266c00fffc440e4b946e5782517))
|
|
||||||
* **rules:** re-scroll directory hash when data refreshes ([6006a65](https://github.com/bitsocialnet/5chan/commit/6006a658fbf4fe625a76c836992dff89540dbe4a))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* **mod queue:** stabilize empty loading state ([33bb1d1](https://github.com/bitsocialnet/5chan/commit/33bb1d1356fbf09693acb5003bcc6e7039a51b90))
|
|
||||||
* **mod queue:** stabilize moderation subscriptions ([f3565f0](https://github.com/bitsocialnet/5chan/commit/f3565f0dda132c67300c49eba49e868f2fc6bfbd))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.9.2](https://github.com/bitsocialnet/5chan/compare/v0.9.1...v0.9.2) (2026-06-13)
|
## [0.9.2](https://github.com/bitsocialnet/5chan/compare/v0.9.1...v0.9.2) (2026-06-13)
|
||||||
|
|
||||||
|
|
||||||
@@ -23,7 +5,7 @@
|
|||||||
|
|
||||||
* **archive:** preserve button link text color on desktop ([b0193b3](https://github.com/bitsocialnet/5chan/commit/b0193b34beec9993d4ca3cedc259ac2e9bd88460))
|
* **archive:** preserve button link text color on desktop ([b0193b3](https://github.com/bitsocialnet/5chan/commit/b0193b34beec9993d4ca3cedc259ac2e9bd88460))
|
||||||
* **challenge-modal:** center mobile modal in viewport ([2e58961](https://github.com/bitsocialnet/5chan/commit/2e58961cf1d32fa303c042809309172add45eb51))
|
* **challenge-modal:** center mobile modal in viewport ([2e58961](https://github.com/bitsocialnet/5chan/commit/2e58961cf1d32fa303c042809309172add45eb51))
|
||||||
* **challenge-modal:** publish challenge answers with pkc object schema ([591aaa7](https://github.com/bitsocialnet/5chan/commit/591aaa729f05a4b2ff62b86c07ee67c112f4123b))
|
* **challenge-modal:** publish challenge answers with pkc object schema ([591aaa7](https://github.com/bitsocialnet/5chan/commit/591aaa729))
|
||||||
* **deps:** bump react-router-dom to 6.30.4 ([ee5aa78](https://github.com/bitsocialnet/5chan/commit/ee5aa7845edcd66b4bde7d6b09a6018bf40b9974)), closes [#276](https://github.com/bitsocialnet/5chan/issues/276)
|
* **deps:** bump react-router-dom to 6.30.4 ([ee5aa78](https://github.com/bitsocialnet/5chan/commit/ee5aa7845edcd66b4bde7d6b09a6018bf40b9974)), closes [#276](https://github.com/bitsocialnet/5chan/issues/276)
|
||||||
* **deps:** resolve shell-quote critical dependabot alert ([fa7cab0](https://github.com/bitsocialnet/5chan/commit/fa7cab069999c745595d2d50bd4f9c920047963d))
|
* **deps:** resolve shell-quote critical dependabot alert ([fa7cab0](https://github.com/bitsocialnet/5chan/commit/fa7cab069999c745595d2d50bd4f9c920047963d))
|
||||||
* **failed-publish:** keep bracket actions on one line ([9de2e6a](https://github.com/bitsocialnet/5chan/commit/9de2e6a8510d4ec6647ff13ce99bd9e8c22b197a))
|
* **failed-publish:** keep bracket actions on one line ([9de2e6a](https://github.com/bitsocialnet/5chan/commit/9de2e6a8510d4ec6647ff13ce99bd9e8c22b197a))
|
||||||
|
|||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "5chan",
|
"name": "5chan",
|
||||||
"version": "0.9.3",
|
"version": "0.9.2",
|
||||||
"packageManager": "yarn@4.13.0",
|
"packageManager": "yarn@4.13.0",
|
||||||
"description": "A Bitsocial client with an imageboard UI",
|
"description": "A Bitsocial client with an imageboard UI",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -9,14 +9,14 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bbob/parser": "4.3.1",
|
"@bbob/parser": "4.3.1",
|
||||||
"@bitsocial/bitsocial-react-hooks": "0.1.18",
|
"@bitsocial/bitsocial-react-hooks": "0.1.17",
|
||||||
"@capacitor/app": "7.0.1",
|
"@capacitor/app": "7.0.1",
|
||||||
"@capacitor/browser": "7.0.5",
|
"@capacitor/browser": "7.0.5",
|
||||||
"@capacitor/status-bar": "7.0.1",
|
"@capacitor/status-bar": "7.0.1",
|
||||||
"@capawesome/capacitor-android-edge-to-edge-support": "7.2.2",
|
"@capawesome/capacitor-android-edge-to-edge-support": "7.2.2",
|
||||||
"@chenglou/pretext": "0.0.5",
|
"@chenglou/pretext": "0.0.5",
|
||||||
"@floating-ui/react": "0.26.1",
|
"@floating-ui/react": "0.26.1",
|
||||||
"@pkcprotocol/pkc-js": "patch:@pkcprotocol/pkc-js@npm%3A0.0.48#~/.yarn/patches/@pkcprotocol-pkc-js-npm-0.0.48-7f3bbd0d02.patch",
|
"@pkcprotocol/pkc-js": "patch:@pkcprotocol/pkc-js@npm%3A0.0.47#~/.yarn/patches/@pkcprotocol-pkc-js-npm-0.0.47-e2131d72c8.patch",
|
||||||
"@react-spring/web": "10.0.3",
|
"@react-spring/web": "10.0.3",
|
||||||
"@ruffle-rs/ruffle": "0.2.0",
|
"@ruffle-rs/ruffle": "0.2.0",
|
||||||
"@types/node": "20.19.37",
|
"@types/node": "20.19.37",
|
||||||
@@ -187,7 +187,7 @@
|
|||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"follow-redirects": "1.16.0",
|
"follow-redirects": "1.16.0",
|
||||||
"@libp2p/gossipsub": "16.0.2",
|
"@libp2p/gossipsub": "15.0.23",
|
||||||
"@libp2p/kad-dht": "16.2.6",
|
"@libp2p/kad-dht": "16.2.6",
|
||||||
"brace-expansion@npm:^5.0.2": "5.0.6",
|
"brace-expansion@npm:^5.0.2": "5.0.6",
|
||||||
"protobufjs": "7.5.8",
|
"protobufjs": "7.5.8",
|
||||||
@@ -243,7 +243,7 @@
|
|||||||
"yaml@npm:^2.8.2": "2.8.3",
|
"yaml@npm:^2.8.2": "2.8.3",
|
||||||
"use-sync-external-store": "1.6.0",
|
"use-sync-external-store": "1.6.0",
|
||||||
"@electron/notarize@npm:^2.1.0": "patch:@electron/notarize@npm%3A2.5.0#~/.yarn/patches/@electron-notarize-npm-2.5.0-b15dc30c99.patch",
|
"@electron/notarize@npm:^2.1.0": "patch:@electron/notarize@npm%3A2.5.0#~/.yarn/patches/@electron-notarize-npm-2.5.0-b15dc30c99.patch",
|
||||||
"@pkcprotocol/pkc-js@npm:0.0.48": "patch:@pkcprotocol/pkc-js@npm%3A0.0.48#~/.yarn/patches/@pkcprotocol-pkc-js-npm-0.0.48-7f3bbd0d02.patch"
|
"@pkcprotocol/pkc-js@npm:0.0.47": "patch:@pkcprotocol/pkc-js@npm%3A0.0.47#~/.yarn/patches/@pkcprotocol-pkc-js-npm-0.0.47-e2131d72c8.patch"
|
||||||
},
|
},
|
||||||
"main": "electron/main.js",
|
"main": "electron/main.js",
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|||||||
+1
-19
@@ -1182,24 +1182,6 @@ Avoid GitHub MCP and browser MCP servers for this project because they add signi
|
|||||||
Source: https://github.com/bitsocialnet/5chan/blob/master/CHANGELOG.md
|
Source: https://github.com/bitsocialnet/5chan/blob/master/CHANGELOG.md
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
## [0.9.3](https://github.com/bitsocialnet/5chan/compare/v0.9.2...v0.9.3) (2026-06-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **ci:** keep raw board tests side-effect free ([75dd7a8](https://github.com/bitsocialnet/5chan/commit/75dd7a84967cb3c99da37780fb31bb6a947d7d57))
|
|
||||||
* **pubsub:** avoid false browser p2p provider failures ([10015de](https://github.com/bitsocialnet/5chan/commit/10015de6b925595694ce1abae547e628b169bf35))
|
|
||||||
* **release:** align blotter and release copy with LaTeX in /sci/ ([3577673](https://github.com/bitsocialnet/5chan/commit/35776737f2479266c00fffc440e4b946e5782517))
|
|
||||||
* **rules:** re-scroll directory hash when data refreshes ([6006a65](https://github.com/bitsocialnet/5chan/commit/6006a658fbf4fe625a76c836992dff89540dbe4a))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* **mod queue:** stabilize empty loading state ([33bb1d1](https://github.com/bitsocialnet/5chan/commit/33bb1d1356fbf09693acb5003bcc6e7039a51b90))
|
|
||||||
* **mod queue:** stabilize moderation subscriptions ([f3565f0](https://github.com/bitsocialnet/5chan/commit/f3565f0dda132c67300c49eba49e868f2fc6bfbd))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.9.2](https://github.com/bitsocialnet/5chan/compare/v0.9.1...v0.9.2) (2026-06-13)
|
## [0.9.2](https://github.com/bitsocialnet/5chan/compare/v0.9.1...v0.9.2) (2026-06-13)
|
||||||
|
|
||||||
|
|
||||||
@@ -1207,7 +1189,7 @@ Source: https://github.com/bitsocialnet/5chan/blob/master/CHANGELOG.md
|
|||||||
|
|
||||||
* **archive:** preserve button link text color on desktop ([b0193b3](https://github.com/bitsocialnet/5chan/commit/b0193b34beec9993d4ca3cedc259ac2e9bd88460))
|
* **archive:** preserve button link text color on desktop ([b0193b3](https://github.com/bitsocialnet/5chan/commit/b0193b34beec9993d4ca3cedc259ac2e9bd88460))
|
||||||
* **challenge-modal:** center mobile modal in viewport ([2e58961](https://github.com/bitsocialnet/5chan/commit/2e58961cf1d32fa303c042809309172add45eb51))
|
* **challenge-modal:** center mobile modal in viewport ([2e58961](https://github.com/bitsocialnet/5chan/commit/2e58961cf1d32fa303c042809309172add45eb51))
|
||||||
* **challenge-modal:** publish challenge answers with pkc object schema ([591aaa7](https://github.com/bitsocialnet/5chan/commit/591aaa729f05a4b2ff62b86c07ee67c112f4123b))
|
* **challenge-modal:** publish challenge answers with pkc object schema ([591aaa7](https://github.com/bitsocialnet/5chan/commit/591aaa729))
|
||||||
* **deps:** bump react-router-dom to 6.30.4 ([ee5aa78](https://github.com/bitsocialnet/5chan/commit/ee5aa7845edcd66b4bde7d6b09a6018bf40b9974)), closes [#276](https://github.com/bitsocialnet/5chan/issues/276)
|
* **deps:** bump react-router-dom to 6.30.4 ([ee5aa78](https://github.com/bitsocialnet/5chan/commit/ee5aa7845edcd66b4bde7d6b09a6018bf40b9974)), closes [#276](https://github.com/bitsocialnet/5chan/issues/276)
|
||||||
* **deps:** resolve shell-quote critical dependabot alert ([fa7cab0](https://github.com/bitsocialnet/5chan/commit/fa7cab069999c745595d2d50bd4f9c920047963d))
|
* **deps:** resolve shell-quote critical dependabot alert ([fa7cab0](https://github.com/bitsocialnet/5chan/commit/fa7cab069999c745595d2d50bd4f9c920047963d))
|
||||||
* **failed-publish:** keep bracket actions on one line ([9de2e6a](https://github.com/bitsocialnet/5chan/commit/9de2e6a8510d4ec6647ff13ce99bd9e8c22b197a))
|
* **failed-publish:** keep bracket actions on one line ([9de2e6a](https://github.com/bitsocialnet/5chan/commit/9de2e6a8510d4ec6647ff13ce99bd9e8c22b197a))
|
||||||
|
|||||||
+1
-1
@@ -47,5 +47,5 @@ This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it
|
|||||||
|
|
||||||
## Optional
|
## Optional
|
||||||
|
|
||||||
- [Changelog](https://github.com/bitsocialnet/5chan/blob/master/CHANGELOG.md): * **ci:** keep raw board tests side-effect free ([75dd7a8](https://github.com/bitsocialnet/5chan/commit/75dd7a84967cb3c99da37780fb31bb6a947d7d57)) * **pubsub:** avoid false browser p2p provider failures ([10015de](htt...
|
- [Changelog](https://github.com/bitsocialnet/5chan/blob/master/CHANGELOG.md): * **archive:** preserve button link text color on desktop ([b0193b3](https://github.com/bitsocialnet/5chan/commit/b0193b34beec9993d4ca3cedc259ac2e9bd88460)) * **challenge-modal:** center mobile modal in viewport ([2e5...
|
||||||
- [Upload Automation Retest Checklist](https://github.com/bitsocialnet/5chan/blob/master/docs/upload-automation-retest-checklist.md): Retest checklist for Android and desktop after changes to media upload automation (`MediaUploadAutomationRunner`, `MediaUploadRecipes`, `upload-orchestrator`, etc.).
|
- [Upload Automation Retest Checklist](https://github.com/bitsocialnet/5chan/blob/master/docs/upload-automation-retest-checklist.md): Retest checklist for Android and desktop after changes to media upload automation (`MediaUploadAutomationRunner`, `MediaUploadRecipes`, `upload-orchestrator`, etc.).
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ const downloads = [macSection, winSection, linuxSection, androidSection, htmlSec
|
|||||||
|
|
||||||
// One-liner summary of what changed in this release. Update before each release.
|
// One-liner summary of what changed in this release. Update before each release.
|
||||||
const oneLinerDescription =
|
const oneLinerDescription =
|
||||||
'This release fixes browser P2P posting errors, improves moderation queue responsiveness, and keeps board rule navigation in place after refreshes.';
|
'This release ships signed and notarized macOS desktop apps, adds LaTeX in /sci/, shows board subtitles on the All view, and improves YouTube thumbnails alongside moderation queue, challenge modal, and media playback fixes.';
|
||||||
|
|
||||||
const releaseBody = `${oneLinerDescription}
|
const releaseBody = `${oneLinerDescription}
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ describe('SettingsModal', () => {
|
|||||||
expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).toBeNull();
|
expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('opens the p2p stats section from its hash', () => {
|
it('opens the p2p stats section from its hash when browser pure p2p is enabled', () => {
|
||||||
render('/all/settings#p2p-stats-settings');
|
render('/all/settings#p2p-stats-settings');
|
||||||
|
|
||||||
expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull();
|
expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull();
|
||||||
|
|||||||
+43
-23
@@ -81,12 +81,6 @@ const clickButton = async (text: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSaveAdvancedSettingsButton = () => {
|
|
||||||
const button = Array.from(container.querySelectorAll('button')).find((candidate) => candidate.textContent === 'save_advanced_settings');
|
|
||||||
expect(button).toBeTruthy();
|
|
||||||
return button as HTMLButtonElement;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setTestHostname = (hostname: string) => {
|
const setTestHostname = (hostname: string) => {
|
||||||
Object.defineProperty(window, 'location', {
|
Object.defineProperty(window, 'location', {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
@@ -210,38 +204,30 @@ describe('AdvancedSettings', () => {
|
|||||||
expect(textInputs[2]?.value).toBe('/tmp/connected-node');
|
expect(textInputs[2]?.value).toBe('/tmp/connected-node');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides gateway mode settings while browser pure p2p is enabled', async () => {
|
it('shows pure p2p browser mode checked by default', async () => {
|
||||||
await renderSettings(false);
|
await renderSettings(false);
|
||||||
|
|
||||||
expect(container.textContent).not.toContain('advanced_ipfs_gateways');
|
expect(container.textContent).not.toContain('advanced_ipfs_gateways');
|
||||||
expect(container.textContent).not.toContain('advanced_pubsub_providers');
|
expect(container.textContent).not.toContain('advanced_pubsub_providers');
|
||||||
expect(container.textContent).toContain('advanced_http_routers');
|
expect(container.textContent).toContain('advanced_http_routers');
|
||||||
expect(container.textContent).toContain('advanced_full_node_websocket_rpc');
|
expect(container.textContent).toContain('advanced_full_node_websocket_rpc');
|
||||||
|
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
||||||
|
expect(checkbox?.checked).toBe(true);
|
||||||
|
|
||||||
const nodeRpcInput = Array.from(container.querySelectorAll<HTMLInputElement>('input[type="text"]')).find(
|
const nodeRpcInput = Array.from(container.querySelectorAll<HTMLInputElement>('input[type="text"]')).find(
|
||||||
(input) => input.placeholder === 'advanced_p2p_rpc_placeholder',
|
(input) => input.placeholder === 'advanced_p2p_rpc_placeholder',
|
||||||
);
|
);
|
||||||
expect(nodeRpcInput).toBeTruthy();
|
expect(nodeRpcInput).toBeTruthy();
|
||||||
|
|
||||||
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
|
||||||
await act(async () => {
|
|
||||||
checkbox?.click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.textContent).toContain('advanced_ipfs_gateways');
|
it('saves browser pure p2p settings when the toggle is turned on', async () => {
|
||||||
expect(container.textContent).toContain('advanced_pubsub_providers');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('saves the browser pure p2p toggle through advanced settings', async () => {
|
|
||||||
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false');
|
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false');
|
||||||
|
|
||||||
await renderSettings(false);
|
await renderSettings(false);
|
||||||
|
|
||||||
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
||||||
expect(checkbox?.checked).toBe(false);
|
expect(checkbox?.checked).toBe(false);
|
||||||
expect(container.textContent).not.toContain('pure P2P:');
|
|
||||||
expect(checkbox?.closest('label')?.nextElementSibling?.textContent).toBe('enable_pure_p2p_tip');
|
expect(checkbox?.closest('label')?.nextElementSibling?.textContent).toBe('enable_pure_p2p_tip');
|
||||||
expect(getSaveAdvancedSettingsButton().previousElementSibling).toBe(checkbox?.closest('div'));
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
checkbox?.click();
|
checkbox?.click();
|
||||||
@@ -252,10 +238,10 @@ describe('AdvancedSettings', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
pkcOptions: expect.objectContaining({
|
pkcOptions: expect.objectContaining({
|
||||||
httpRoutersOptions: ['https://router.old.example'],
|
httpRoutersOptions: ['https://router.old.example'],
|
||||||
ipfsGatewayUrls: [],
|
ipfsGatewayUrls: undefined,
|
||||||
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
pkcRpcClientsOptions: undefined,
|
pkcRpcClientsOptions: undefined,
|
||||||
pubsubKuboRpcClientsOptions: [],
|
pubsubKuboRpcClientsOptions: undefined,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -263,7 +249,42 @@ describe('AdvancedSettings', () => {
|
|||||||
expect(reloadMock).toHaveBeenCalledOnce();
|
expect(reloadMock).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows browser pure p2p to be disabled on p2p subdomains', async () => {
|
it('saves gateway defaults when the browser pure p2p setting is turned off', async () => {
|
||||||
|
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'true');
|
||||||
|
testState.account = {
|
||||||
|
mediaIpfsGatewayUrl: 'https://media.old.example',
|
||||||
|
pkcOptions: {
|
||||||
|
httpRoutersOptions: ['https://peers.pleb.bot'],
|
||||||
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await renderSettings(false);
|
||||||
|
|
||||||
|
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
||||||
|
expect(checkbox?.checked).toBe(true);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
checkbox?.click();
|
||||||
|
});
|
||||||
|
await clickButton('save_advanced_settings');
|
||||||
|
|
||||||
|
expect(testState.setAccountMock).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
pkcOptions: expect.objectContaining({
|
||||||
|
httpRoutersOptions: ['https://peers.pleb.bot'],
|
||||||
|
ipfsGatewayUrls: ['https://ipfsgateway.xyz', 'https://gateway.plebpubsub.xyz', 'https://gateway.forumindex.com'],
|
||||||
|
libp2pJsClientsOptions: undefined,
|
||||||
|
pkcRpcClientsOptions: undefined,
|
||||||
|
pubsubKuboRpcClientsOptions: ['https://pubsubprovider.xyz/api/v0', 'https://plebpubsub.xyz/api/v0', 'https://rannithepleb.com/api/v0'],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(localStorage.getItem('5chan:pure-p2p-browser-enabled')).toBe('false');
|
||||||
|
expect(reloadMock).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preserves custom browser gateway providers while pure p2p is unavailable', async () => {
|
||||||
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false');
|
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'false');
|
||||||
setTestHostname('p2p.5chan.app');
|
setTestHostname('p2p.5chan.app');
|
||||||
|
|
||||||
@@ -271,7 +292,6 @@ describe('AdvancedSettings', () => {
|
|||||||
|
|
||||||
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
const checkbox = container.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
||||||
expect(checkbox?.checked).toBe(false);
|
expect(checkbox?.checked).toBe(false);
|
||||||
expect(checkbox?.disabled).toBe(false);
|
|
||||||
|
|
||||||
await clickButton('save_advanced_settings');
|
await clickButton('save_advanced_settings');
|
||||||
|
|
||||||
@@ -288,7 +308,7 @@ describe('AdvancedSettings', () => {
|
|||||||
expect(localStorage.getItem('5chan:pure-p2p-browser-enabled')).toBe('false');
|
expect(localStorage.getItem('5chan:pure-p2p-browser-enabled')).toBe('false');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('saves gateway mode defaults when browser pure p2p is disabled', async () => {
|
it('saves gateway mode defaults when browser pure p2p settings have no gateway endpoints', async () => {
|
||||||
testState.account = {
|
testState.account = {
|
||||||
mediaIpfsGatewayUrl: 'https://media.old.example',
|
mediaIpfsGatewayUrl: 'https://media.old.example',
|
||||||
pkcOptions: {
|
pkcOptions: {
|
||||||
|
|||||||
@@ -248,6 +248,23 @@ const getTrimmedLines = (value: string | undefined): string[] | undefined => {
|
|||||||
}, []);
|
}, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const applyBrowserGatewayPkcOptions = (
|
||||||
|
pkcOptions: AccountProtocolOptions,
|
||||||
|
ipfsGatewayUrls: string[] | undefined,
|
||||||
|
pubsubKuboRpcClientsOptions: string[] | undefined,
|
||||||
|
httpRoutersOptions: string[] | undefined,
|
||||||
|
) => {
|
||||||
|
const gatewayOptions = getBrowserGatewayPkcOptions();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...pkcOptions,
|
||||||
|
...gatewayOptions,
|
||||||
|
ipfsGatewayUrls: ipfsGatewayUrls?.length ? ipfsGatewayUrls : gatewayOptions.ipfsGatewayUrls,
|
||||||
|
pubsubKuboRpcClientsOptions: pubsubKuboRpcClientsOptions?.length ? pubsubKuboRpcClientsOptions : gatewayOptions.pubsubKuboRpcClientsOptions,
|
||||||
|
httpRoutersOptions: httpRoutersOptions?.length ? httpRoutersOptions : gatewayOptions.httpRoutersOptions,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const AdvancedSettings = () => {
|
const AdvancedSettings = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const account = useAccount() as AccountShape | undefined;
|
const account = useAccount() as AccountShape | undefined;
|
||||||
@@ -305,14 +322,7 @@ const AdvancedSettings = () => {
|
|||||||
pkcRpcClientsOptions: undefined,
|
pkcRpcClientsOptions: undefined,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const gatewayOptions = getBrowserGatewayPkcOptions();
|
pkcOptions = applyBrowserGatewayPkcOptions(pkcOptions, ipfsGatewayUrls, pubsubKuboRpcClientsOptions, httpRoutersOptions);
|
||||||
pkcOptions = {
|
|
||||||
...pkcOptions,
|
|
||||||
...gatewayOptions,
|
|
||||||
ipfsGatewayUrls: ipfsGatewayUrls?.length ? ipfsGatewayUrls : gatewayOptions.ipfsGatewayUrls,
|
|
||||||
pubsubKuboRpcClientsOptions: pubsubKuboRpcClientsOptions?.length ? pubsubKuboRpcClientsOptions : gatewayOptions.pubsubKuboRpcClientsOptions,
|
|
||||||
httpRoutersOptions: httpRoutersOptions?.length ? httpRoutersOptions : gatewayOptions.httpRoutersOptions,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
{
|
{
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
|
||||||
"id": "release-0.9.3",
|
|
||||||
"kind": "release",
|
|
||||||
"timestamp": 1781611200,
|
|
||||||
"message": "v0.9.3: More reliable browser posting",
|
|
||||||
"version": "0.9.3"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "release-0.9.2",
|
"id": "release-0.9.2",
|
||||||
"kind": "release",
|
"kind": "release",
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ describe('use-state-string', () => {
|
|||||||
expect(latestValue).toBe('Resolving address, downloading board from peers');
|
expect(latestValue).toBe('Resolving address, downloading board from peers');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formats browser p2p fallback publishing states as peer downloads', () => {
|
it('formats browser p2p fallback publishing states as peer downloads when pure p2p is enabled', () => {
|
||||||
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'true');
|
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'true');
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -144,7 +144,7 @@ describe('use-state-string', () => {
|
|||||||
expect(latestValue).toBe('Downloading board via IPFS');
|
expect(latestValue).toBe('Downloading board via IPFS');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formats browser p2p single-board feed fallback states as peer downloads', () => {
|
it('formats browser p2p single-board feed fallback states as peer downloads when pure p2p is enabled', () => {
|
||||||
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'true');
|
localStorage.setItem('5chan:pure-p2p-browser-enabled', 'true');
|
||||||
testState.community = {
|
testState.community = {
|
||||||
state: 'updating',
|
state: 'updating',
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { describe, expect, it } from 'vitest';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
configureP2PBrowserPkcOptions,
|
configureP2PBrowserPkcOptions,
|
||||||
|
getBrowserGatewayPkcOptions,
|
||||||
getPureP2PBrowserPreference,
|
getPureP2PBrowserPreference,
|
||||||
P2P_BROWSER_PKC_OPTIONS,
|
|
||||||
PURE_P2P_BROWSER_SETTING_KEY,
|
PURE_P2P_BROWSER_SETTING_KEY,
|
||||||
setPureP2PBrowserPreference,
|
setPureP2PBrowserPreference,
|
||||||
shouldUsePureP2PBrowser,
|
shouldUsePureP2PBrowser,
|
||||||
@@ -17,36 +17,54 @@ const createStorage = (values: Record<string, string | undefined> = {}) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('p2p-browser-config', () => {
|
describe('p2p-browser-config', () => {
|
||||||
|
const defaultHttpRouters = ['https://peers.plebpubsub.xyz', 'https://routing.lol', 'https://peers.pleb.bot'];
|
||||||
|
|
||||||
it('configures browser PKC options for pure p2p by default', () => {
|
it('configures browser PKC options for pure p2p by default', () => {
|
||||||
|
const chainProviders = {
|
||||||
|
eth: { urls: ['https://eth.example'], chainId: 1 },
|
||||||
|
};
|
||||||
const targetWindow = {
|
const targetWindow = {
|
||||||
location: { hostname: '5chan.app' },
|
location: { hostname: '5chan.app' },
|
||||||
localStorage: createStorage(),
|
localStorage: createStorage(),
|
||||||
defaultPkcOptions: {
|
defaultPkcOptions: {
|
||||||
|
chainProviders,
|
||||||
ipfsGatewayUrls: ['https://gateway.example'],
|
ipfsGatewayUrls: ['https://gateway.example'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(shouldUsePureP2PBrowser(targetWindow)).toBe(true);
|
expect(shouldUsePureP2PBrowser(targetWindow)).toBe(true);
|
||||||
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(true);
|
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(true);
|
||||||
expect(targetWindow.defaultPkcOptions).toEqual(P2P_BROWSER_PKC_OPTIONS);
|
expect(targetWindow.defaultPkcOptions).toMatchObject({
|
||||||
|
chainProviders,
|
||||||
|
httpRoutersOptions: defaultHttpRouters,
|
||||||
|
ipfsGatewayUrls: undefined,
|
||||||
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
|
pubsubKuboRpcClientsOptions: undefined,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('respects disabled pure p2p preference on p2p subdomains', () => {
|
it('configures browser PKC options for gateway mode when pure p2p is explicitly disabled', () => {
|
||||||
const defaultPkcOptions = {
|
const chainProviders = {
|
||||||
ipfsGatewayUrls: ['https://gateway.example'],
|
eth: { urls: ['https://eth.example'], chainId: 1 },
|
||||||
};
|
};
|
||||||
const targetWindow = {
|
const targetWindow = {
|
||||||
location: { hostname: 'p2p.5chan.app' },
|
location: { hostname: '5chan.app' },
|
||||||
localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'false' }),
|
localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'false' }),
|
||||||
defaultPkcOptions,
|
defaultPkcOptions: {
|
||||||
|
chainProviders,
|
||||||
|
ipfsGatewayUrls: ['https://gateway.example'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(shouldUsePureP2PBrowser(targetWindow)).toBe(false);
|
expect(shouldUsePureP2PBrowser(targetWindow)).toBe(false);
|
||||||
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(false);
|
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(false);
|
||||||
expect(targetWindow.defaultPkcOptions).toBe(defaultPkcOptions);
|
expect(targetWindow.defaultPkcOptions).toEqual({
|
||||||
|
chainProviders,
|
||||||
|
...getBrowserGatewayPkcOptions(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('configures browser PKC options when pure p2p is enabled', () => {
|
it('configures browser PKC options when pure p2p is explicitly enabled', () => {
|
||||||
const targetWindow = {
|
const targetWindow = {
|
||||||
location: { hostname: '5chan.app' },
|
location: { hostname: '5chan.app' },
|
||||||
localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'true' }),
|
localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'true' }),
|
||||||
@@ -55,22 +73,14 @@ describe('p2p-browser-config', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
expect(shouldUsePureP2PBrowser(targetWindow)).toBe(true);
|
||||||
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(true);
|
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(true);
|
||||||
expect(targetWindow.defaultPkcOptions).toEqual(P2P_BROWSER_PKC_OPTIONS);
|
expect(targetWindow.defaultPkcOptions).toMatchObject({
|
||||||
|
httpRoutersOptions: defaultHttpRouters,
|
||||||
|
ipfsGatewayUrls: undefined,
|
||||||
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
|
pubsubKuboRpcClientsOptions: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
it('leaves browser PKC options untouched when pure p2p is disabled', () => {
|
|
||||||
const defaultPkcOptions = {
|
|
||||||
ipfsGatewayUrls: ['https://gateway.example'],
|
|
||||||
};
|
|
||||||
const targetWindow = {
|
|
||||||
location: { hostname: '5chan.app' },
|
|
||||||
localStorage: createStorage({ [PURE_P2P_BROWSER_SETTING_KEY]: 'false' }),
|
|
||||||
defaultPkcOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(configureP2PBrowserPkcOptions(targetWindow)).toBe(false);
|
|
||||||
expect(targetWindow.defaultPkcOptions).toBe(defaultPkcOptions);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('leaves electron defaults untouched', () => {
|
it('leaves electron defaults untouched', () => {
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ const browserWindowWithDisabledPureP2P = {
|
|||||||
},
|
},
|
||||||
} as unknown as Window;
|
} as unknown as Window;
|
||||||
|
|
||||||
|
const browserWindowWithEnabledPureP2P = {
|
||||||
|
electronApi: undefined,
|
||||||
|
isElectron: false,
|
||||||
|
location: { hostname: '5chan.app' },
|
||||||
|
localStorage: {
|
||||||
|
getItem: () => 'true',
|
||||||
|
setItem: () => undefined,
|
||||||
|
},
|
||||||
|
} as unknown as Window;
|
||||||
|
|
||||||
const electronWindow = {
|
const electronWindow = {
|
||||||
electronApi: { isElectron: true },
|
electronApi: { isElectron: true },
|
||||||
isElectron: true,
|
isElectron: true,
|
||||||
@@ -56,10 +66,14 @@ describe('p2p-runtime', () => {
|
|||||||
expect(getP2PRuntimeMode(account, browserWindow)).toBe('full-node-rpc');
|
expect(getP2PRuntimeMode(account, browserWindow)).toBe('full-node-rpc');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows p2p settings in browsers when pure p2p is enabled by default', () => {
|
it('keeps browser pure p2p on by default while allowing gateway mode when configured', () => {
|
||||||
expect(shouldShowP2PSettingsSection(undefined, browserWindow)).toBe(true);
|
expect(shouldShowP2PSettingsSection(undefined, browserWindow)).toBe(true);
|
||||||
expect(shouldShowP2PSettingsSection({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(true);
|
expect(shouldShowP2PSettingsSection({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(true);
|
||||||
expect(isBrowserPureP2PEnabled({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(true);
|
expect(isBrowserPureP2PEnabled({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindow)).toBe(true);
|
||||||
|
expect(shouldShowP2PSettingsSection({ pkcOptions: { libp2pJsClientsOptions: [{ key: 'libp2pjs' }] } }, browserWindow)).toBe(true);
|
||||||
|
expect(isBrowserPureP2PEnabled({ pkcOptions: { libp2pJsClientsOptions: [{ key: 'libp2pjs' }] } }, browserWindow)).toBe(true);
|
||||||
|
expect(shouldShowP2PSettingsSection({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindowWithEnabledPureP2P)).toBe(true);
|
||||||
|
expect(isBrowserPureP2PEnabled({ pkcOptions: { ipfsGatewayUrls: ['https://gateway.example'] } }, browserWindowWithEnabledPureP2P)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows browser gateway mode when pure p2p is disabled', () => {
|
it('allows browser gateway mode when pure p2p is disabled', () => {
|
||||||
@@ -88,13 +102,15 @@ describe('p2p-runtime', () => {
|
|||||||
|
|
||||||
expect(getBrowserPureP2PAccountOptions(account)).toMatchObject({
|
expect(getBrowserPureP2PAccountOptions(account)).toMatchObject({
|
||||||
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
ipfsGatewayUrls: [],
|
ipfsGatewayUrls: undefined,
|
||||||
pkcRpcClientsOptions: undefined,
|
pkcRpcClientsOptions: undefined,
|
||||||
});
|
});
|
||||||
expect(getBrowserGatewayAccountOptions(account)).toMatchObject({
|
expect(getBrowserGatewayAccountOptions(account)).toMatchObject({
|
||||||
ipfsGatewayUrls: ['https://ipfsgateway.xyz', 'https://gateway.plebpubsub.xyz', 'https://gateway.forumindex.com'],
|
httpRoutersOptions: ['https://custom-router.example'],
|
||||||
|
ipfsGatewayUrls: ['https://gateway.example'],
|
||||||
libp2pJsClientsOptions: undefined,
|
libp2pJsClientsOptions: undefined,
|
||||||
pkcRpcClientsOptions: undefined,
|
pkcRpcClientsOptions: undefined,
|
||||||
|
pubsubKuboRpcClientsOptions: ['https://pubsubprovider.xyz/api/v0', 'https://plebpubsub.xyz/api/v0', 'https://rannithepleb.com/api/v0'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
export const PURE_P2P_BROWSER_SETTING_KEY = '5chan:pure-p2p-browser-enabled';
|
export const PURE_P2P_BROWSER_SETTING_KEY = '5chan:pure-p2p-browser-enabled';
|
||||||
|
export const BROWSER_PURE_P2P_DEFAULT_ENABLED = true;
|
||||||
|
|
||||||
export const P2P_BROWSER_PKC_OPTIONS = {
|
export const P2P_BROWSER_PKC_OPTIONS = {
|
||||||
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
ipfsGatewayUrls: [],
|
ipfsGatewayUrls: undefined,
|
||||||
kuboRpcClientsOptions: undefined,
|
kuboRpcClientsOptions: undefined,
|
||||||
pubsubHttpClientsOptions: undefined,
|
pubsubHttpClientsOptions: undefined,
|
||||||
pubsubKuboRpcClientsOptions: [],
|
pubsubKuboRpcClientsOptions: undefined,
|
||||||
httpRoutersOptions: ['https://peers.pleb.bot', 'https://peers.forumindex.com'],
|
httpRoutersOptions: ['https://peers.plebpubsub.xyz', 'https://routing.lol', 'https://peers.pleb.bot'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const GATEWAY_BROWSER_PKC_OPTIONS = {
|
const GATEWAY_BROWSER_PKC_OPTIONS = {
|
||||||
@@ -29,8 +30,6 @@ type P2PBrowserConfigWindow = {
|
|||||||
export const getBrowserPureP2PPkcOptions = () => ({
|
export const getBrowserPureP2PPkcOptions = () => ({
|
||||||
...P2P_BROWSER_PKC_OPTIONS,
|
...P2P_BROWSER_PKC_OPTIONS,
|
||||||
libp2pJsClientsOptions: P2P_BROWSER_PKC_OPTIONS.libp2pJsClientsOptions.map((options) => ({ ...options })),
|
libp2pJsClientsOptions: P2P_BROWSER_PKC_OPTIONS.libp2pJsClientsOptions.map((options) => ({ ...options })),
|
||||||
ipfsGatewayUrls: [...P2P_BROWSER_PKC_OPTIONS.ipfsGatewayUrls],
|
|
||||||
pubsubKuboRpcClientsOptions: [...P2P_BROWSER_PKC_OPTIONS.pubsubKuboRpcClientsOptions],
|
|
||||||
httpRoutersOptions: [...P2P_BROWSER_PKC_OPTIONS.httpRoutersOptions],
|
httpRoutersOptions: [...P2P_BROWSER_PKC_OPTIONS.httpRoutersOptions],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,17 +62,26 @@ export const setPureP2PBrowserPreference = (enabled: boolean, targetWindow: P2PB
|
|||||||
|
|
||||||
export const isElectronRuntime = (targetWindow: P2PBrowserConfigWindow = window) => targetWindow.electronApi?.isElectron === true || targetWindow.isElectron === true;
|
export const isElectronRuntime = (targetWindow: P2PBrowserConfigWindow = window) => targetWindow.electronApi?.isElectron === true || targetWindow.isElectron === true;
|
||||||
|
|
||||||
|
export const canUsePureP2PBrowser = (targetWindow: P2PBrowserConfigWindow = window) => !isElectronRuntime(targetWindow);
|
||||||
|
|
||||||
export const shouldUsePureP2PBrowser = (targetWindow: P2PBrowserConfigWindow = window) => {
|
export const shouldUsePureP2PBrowser = (targetWindow: P2PBrowserConfigWindow = window) => {
|
||||||
if (isElectronRuntime(targetWindow)) return false;
|
if (!canUsePureP2PBrowser(targetWindow)) return false;
|
||||||
|
|
||||||
const preference = getPureP2PBrowserPreference(targetWindow);
|
const preference = getPureP2PBrowserPreference(targetWindow);
|
||||||
if (preference !== undefined) return preference;
|
if (preference !== undefined) return preference;
|
||||||
|
|
||||||
return true;
|
return BROWSER_PURE_P2P_DEFAULT_ENABLED;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const configureP2PBrowserPkcOptions = (targetWindow: P2PBrowserConfigWindow = window) => {
|
export const configureP2PBrowserPkcOptions = (targetWindow: P2PBrowserConfigWindow = window) => {
|
||||||
if (!shouldUsePureP2PBrowser(targetWindow)) {
|
if (!shouldUsePureP2PBrowser(targetWindow)) {
|
||||||
|
if (canUsePureP2PBrowser(targetWindow)) {
|
||||||
|
targetWindow.defaultPkcOptions = {
|
||||||
|
...targetWindow.defaultPkcOptions,
|
||||||
|
...getBrowserGatewayPkcOptions(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-8
@@ -1,4 +1,4 @@
|
|||||||
import { getBrowserGatewayPkcOptions, getBrowserPureP2PPkcOptions, isElectronRuntime, shouldUsePureP2PBrowser } from './p2p-browser-config';
|
import { canUsePureP2PBrowser, getBrowserGatewayPkcOptions, getBrowserPureP2PPkcOptions, isElectronRuntime, shouldUsePureP2PBrowser } from './p2p-browser-config';
|
||||||
|
|
||||||
export const P2P_STATS_SECTION_ID = 'p2p-stats-settings';
|
export const P2P_STATS_SECTION_ID = 'p2p-stats-settings';
|
||||||
|
|
||||||
@@ -46,10 +46,13 @@ export const getP2PRuntimeMode = (account?: unknown, targetWindow: Window = wind
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const canConfigureBrowserPureP2P = (targetWindow: Window = window) => !isElectronRuntime(targetWindow);
|
export const canConfigureBrowserPureP2P = (targetWindow: Window = window) => canUsePureP2PBrowser(targetWindow);
|
||||||
|
|
||||||
export const shouldShowP2PSettingsSection = (account?: unknown, targetWindow: Window = window) =>
|
export const shouldShowP2PSettingsSection = (account?: unknown, targetWindow: Window = window) => {
|
||||||
getP2PRuntimeMode(account, targetWindow) !== null || (canConfigureBrowserPureP2P(targetWindow) && isBrowserPureP2PEnabled(account, targetWindow));
|
const runtimeMode = getP2PRuntimeMode(account, targetWindow);
|
||||||
|
if (runtimeMode === 'electron-kubo-rpc' || runtimeMode === 'full-node-rpc') return true;
|
||||||
|
return canConfigureBrowserPureP2P(targetWindow) && (runtimeMode === 'browser-libp2p' || isBrowserPureP2PEnabled(account, targetWindow));
|
||||||
|
};
|
||||||
|
|
||||||
export const isBrowserPureP2PEnabled = (account?: unknown, targetWindow: Window = window) => {
|
export const isBrowserPureP2PEnabled = (account?: unknown, targetWindow: Window = window) => {
|
||||||
if (!canConfigureBrowserPureP2P(targetWindow)) return false;
|
if (!canConfigureBrowserPureP2P(targetWindow)) return false;
|
||||||
@@ -63,8 +66,18 @@ export const getBrowserPureP2PAccountOptions = (account?: unknown) => ({
|
|||||||
pkcRpcClientsOptions: undefined,
|
pkcRpcClientsOptions: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getBrowserGatewayAccountOptions = (account?: unknown) => ({
|
export const getBrowserGatewayAccountOptions = (account?: unknown) => {
|
||||||
...toAccountShape(account)?.pkcOptions,
|
const protocolOptions = toAccountShape(account)?.pkcOptions;
|
||||||
...getBrowserGatewayPkcOptions(),
|
const gatewayOptions = getBrowserGatewayPkcOptions();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...protocolOptions,
|
||||||
|
...gatewayOptions,
|
||||||
|
ipfsGatewayUrls: hasArrayItems(protocolOptions?.ipfsGatewayUrls) ? protocolOptions?.ipfsGatewayUrls : gatewayOptions.ipfsGatewayUrls,
|
||||||
|
pubsubKuboRpcClientsOptions: hasArrayItems(protocolOptions?.pubsubKuboRpcClientsOptions)
|
||||||
|
? protocolOptions?.pubsubKuboRpcClientsOptions
|
||||||
|
: gatewayOptions.pubsubKuboRpcClientsOptions,
|
||||||
|
httpRoutersOptions: hasArrayItems(protocolOptions?.httpRoutersOptions) ? protocolOptions?.httpRoutersOptions : gatewayOptions.httpRoutersOptions,
|
||||||
pkcRpcClientsOptions: undefined,
|
pkcRpcClientsOptions: undefined,
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ describe('Rules', () => {
|
|||||||
expect(scrollIntoViewMock).toHaveBeenCalled();
|
expect(scrollIntoViewMock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows a friendly loading state string while a board over P2P is downloading', async () => {
|
it('shows a friendly loading state string while a board is downloading from peers', async () => {
|
||||||
testState.communities = {
|
testState.communities = {
|
||||||
'custom-board.eth': {
|
'custom-board.eth': {
|
||||||
state: 'fetching-ipns',
|
state: 'fetching-ipns',
|
||||||
|
|||||||
Reference in New Issue
Block a user