@lat-murmeldjur/weeb_3 0.0.321001 → 0.0.322001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -35
- package/package.json +1 -4
- package/service.js +19 -77
- package/snippets/weeb_3-03f860286800ffdb/static/hls_loader.js +0 -2
- package/weeb_3.d.ts +42 -268
- package/weeb_3.js +596 -1518
- package/weeb_3_bg.wasm +0 -0
- package/weeb_3_bg.wasm.d.ts +42 -123
package/README.md
CHANGED
|
@@ -22,43 +22,28 @@ This package contains the browser-targeted WebAssembly build of the `weeb-3` cli
|
|
|
22
22
|
The main exports are:
|
|
23
23
|
|
|
24
24
|
- `Weeb3No103` as the higher-level client interface
|
|
25
|
-
- `BootstrapNode` for defining bootstrap peers
|
|
26
|
-
- `Weeb3` for lower-level direct access to the underlying client
|
|
27
25
|
|
|
28
26
|
The higher-level `Weeb3No103` interface provides the main methods used by the embedding example:
|
|
29
27
|
|
|
30
28
|
- `start(options?)`
|
|
31
|
-
- `connect()`
|
|
32
29
|
- `networkState()`
|
|
33
|
-
- `
|
|
34
|
-
- `switchTestnet()` / `switch_testnet()`
|
|
35
|
-
- `switchNetwork(mode)` / `switch_network(mode)`
|
|
36
|
-
- `connectProfile(mode)` / `connect_profile(mode)`
|
|
30
|
+
- `switchNetwork(mode)`
|
|
37
31
|
- `retrieve(address)`
|
|
38
32
|
- `upload(file, encryption, index_string, add_to_feed, feed_topic)`
|
|
39
33
|
- `uploadWithRedundancy(file, encryption, redundancy_level, index_string, add_to_feed, feed_topic)`
|
|
40
34
|
- `postUploadBytesWithRedundancy(bytes, mime, filename, encryption, redundancy_level, add_to_feed, feed_topic)`
|
|
41
|
-
- `openStreamFeed(owner, topic)`
|
|
42
|
-
- `playHlsStream(owner, topic, media_type, index?)`
|
|
43
|
-
- `attachHlsStream(media, owner, topic, options)`
|
|
44
|
-
- `detachHlsStream()`
|
|
45
|
-
- `configureStreamingRoutes(service_worker_url, route_base)`
|
|
46
35
|
- `renderInterface(container)`
|
|
47
36
|
- `resetStamp()`
|
|
48
37
|
- `postPushChunk(data, soc, chunk_address, stamp)`
|
|
49
38
|
|
|
50
39
|
Sequence-feed indexes use Bee's fixed-width eight-byte big-endian encoding.
|
|
51
40
|
|
|
52
|
-
## HLS streaming
|
|
53
|
-
|
|
54
|
-
HLS playback is an optional dapp integration, not a Bee/Swarm standard. `playHlsStream(...)` displays a stream in the bundled interface after `renderInterface(container)`. For an application-owned `<video>` or `<audio>` element, call `attachHlsStream(media, owner, topic, { start: "beginning" })`; use `"current-window"` for a rolling/live presentation. Call `detachHlsStream()` before removing or replacing that element. The Service Worker must be copied from the package to a same-origin URL whose scope contains the page, then configured with `configureStreamingRoutes(...)`. Canonical mainnet links use `/stream/{owner}/{topic}[/{index}]`; testnet inserts `/testnet` before `/stream`.
|
|
55
|
-
|
|
56
41
|
## Basic usage
|
|
57
42
|
|
|
58
43
|
Call `init()` once before creating a client instance so the WebAssembly module is loaded.
|
|
59
44
|
|
|
60
45
|
```js
|
|
61
|
-
import init, { Weeb3No103
|
|
46
|
+
import init, { Weeb3No103 } from "@lat-murmeldjur/weeb_3";
|
|
62
47
|
|
|
63
48
|
await init();
|
|
64
49
|
|
|
@@ -69,17 +54,12 @@ weeb3node.start();
|
|
|
69
54
|
console.log(await weeb3node.networkState());
|
|
70
55
|
|
|
71
56
|
// Switch explicitly between built-in profiles.
|
|
72
|
-
await weeb3node.switchTestnet();
|
|
73
|
-
await weeb3node.switchMainnet();
|
|
74
|
-
|
|
75
|
-
// Or use the generic form. Accepted values include:
|
|
76
|
-
// "mainnet", "gnosis", "1", "testnet", "sepolia", and "10".
|
|
77
57
|
await weeb3node.switchNetwork("testnet");
|
|
78
58
|
await weeb3node.switchNetwork("mainnet");
|
|
79
59
|
|
|
80
60
|
// You can still start with explicit browser-dialable bootnodes and network id.
|
|
81
61
|
const BOOTSTRAP_NODES = [
|
|
82
|
-
|
|
62
|
+
{ multiaddr: "/ip4/example/tcp/443/wss/p2p/examplePeerId", usable: true },
|
|
83
63
|
];
|
|
84
64
|
|
|
85
65
|
weeb3node.start({
|
|
@@ -96,36 +76,31 @@ weeb3node.start({ testnet: true });
|
|
|
96
76
|
This is a compact npm-import form of the same usage pattern shown in the project's `example.html`:
|
|
97
77
|
|
|
98
78
|
```js
|
|
99
|
-
import init, { Weeb3No103
|
|
79
|
+
import init, { Weeb3No103 } from "@lat-murmeldjur/weeb_3";
|
|
100
80
|
|
|
101
81
|
await init();
|
|
102
82
|
|
|
103
83
|
const weeb3node = new Weeb3No103();
|
|
104
84
|
|
|
105
|
-
await weeb3node.
|
|
85
|
+
await weeb3node.switchNetwork("mainnet");
|
|
106
86
|
|
|
107
87
|
const entries = await weeb3node.retrieve(
|
|
108
88
|
"695fceb3a8c212cd123e2e40d86ec08b52fe4fe6ca46687ce9ea69b8f05471f6aa25b5d4d41bf78b1db3479c048fd5fd8137ba844604821b71786196306b68e7"
|
|
109
89
|
);
|
|
110
90
|
```
|
|
111
91
|
|
|
112
|
-
##
|
|
92
|
+
## Upload API
|
|
113
93
|
|
|
114
94
|
Legacy upload methods use Bee's Medium level. Explicit upload levels are `0` None, `1` Medium, `2` Strong, `3` Insane, and `4` Paranoid. The generated TypeScript declaration exposes this as `UploadRedundancyLevel = 0 | 1 | 2 | 3 | 4`.
|
|
115
95
|
|
|
116
|
-
`renderInterface(container)` includes a Medium-default erasure-coding dropdown. A custom interface can
|
|
96
|
+
`renderInterface(container)` includes a Medium-default erasure-coding dropdown. A custom interface can pass the selected numeric level directly:
|
|
117
97
|
|
|
118
98
|
```js
|
|
119
|
-
import init, {
|
|
120
|
-
Weeb3No103,
|
|
121
|
-
defaultUploadRedundancyLevel,
|
|
122
|
-
uploadRedundancyOptions,
|
|
123
|
-
} from "@lat-murmeldjur/weeb_3";
|
|
99
|
+
import init, { Weeb3No103 } from "@lat-murmeldjur/weeb_3";
|
|
124
100
|
|
|
125
101
|
await init();
|
|
126
102
|
const node = new Weeb3No103();
|
|
127
|
-
const
|
|
128
|
-
const level = defaultUploadRedundancyLevel();
|
|
103
|
+
const level = 1;
|
|
129
104
|
|
|
130
105
|
const result = await node.uploadWithRedundancy(
|
|
131
106
|
file,
|
|
@@ -142,6 +117,5 @@ Retrieval reads the level encoded in the Swarm tree and uses parity when data sh
|
|
|
142
117
|
## Notes
|
|
143
118
|
|
|
144
119
|
- This package is meant for browser applications, not a plain Node.js runtime.
|
|
145
|
-
- Use one active `Weeb3No103` node and HLS session per loaded Wasm module.
|
|
146
120
|
- The package does not publish the standalone site HTML, but `renderInterface(container)` embeds the same interface shell—including its erasure-coding selector—from the Wasm bundle.
|
|
147
121
|
- The full released browser client remains available in the main project repository and on the project site.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@lat-murmeldjur/weeb_3",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "A Swarm client for browsers",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.322001",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -42,9 +42,6 @@
|
|
|
42
42
|
"types": "./weeb_3.d.ts",
|
|
43
43
|
"import": "./weeb_3.js",
|
|
44
44
|
"default": "./weeb_3.js"
|
|
45
|
-
},
|
|
46
|
-
"./service.js": {
|
|
47
|
-
"default": "./service.js"
|
|
48
45
|
}
|
|
49
46
|
},
|
|
50
47
|
"dependencies": {
|
package/service.js
CHANGED
|
@@ -6,13 +6,11 @@ const NETWORK_ROUTE_PREFIXES = ["", "mainnet/", "testnet/"];
|
|
|
6
6
|
const RAW_ROUTE_KINDS = [
|
|
7
7
|
["hls/bytes", "hls-bytes"],
|
|
8
8
|
["bytes", "bytes"],
|
|
9
|
-
["chunks", "chunk"]
|
|
10
|
-
["chunk", "chunk"]
|
|
9
|
+
["chunks", "chunk"]
|
|
11
10
|
];
|
|
12
11
|
const FETCH_TIMEOUT_MS = 240000;
|
|
13
12
|
const SERVICE_WORKER_MARKER = "forwarder-default20";
|
|
14
13
|
const SERVICE_WORKER_PROTOCOL = 5;
|
|
15
|
-
const DEBUG_SERVICE_WORKER = false;
|
|
16
14
|
const MIB_BYTES = 1024 * 1024;
|
|
17
15
|
const STREAM_STORAGE_WINDOW_BYTES = MIB_BYTES / 2;
|
|
18
16
|
const STREAM_LOOKAHEAD_CHUNKS = 8;
|
|
@@ -22,12 +20,6 @@ const CLIENT_RUNTIME_PROBE_TIMEOUT_MS = 1_500;
|
|
|
22
20
|
|
|
23
21
|
console.log(`weeb-3 service worker start ${SERVICE_WORKER_MARKER}`);
|
|
24
22
|
|
|
25
|
-
function debugLog(...args) {
|
|
26
|
-
if (DEBUG_SERVICE_WORKER) {
|
|
27
|
-
console.log(...args);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
23
|
function logServiceWorkerVersion(reason) {
|
|
32
24
|
console.log(`weeb-3 service worker ${reason} ${SERVICE_WORKER_MARKER}`);
|
|
33
25
|
}
|
|
@@ -79,32 +71,16 @@ function isCanonicalStreamTopic(value) {
|
|
|
79
71
|
}
|
|
80
72
|
}
|
|
81
73
|
|
|
82
|
-
function isCanonicalStreamIndex(value) {
|
|
83
|
-
if (value === undefined) {
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
return /^[0-9]+$/.test(value) && BigInt(value) <= 18446744073709551615n;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
74
|
function isDirectShareShellPath(pathname) {
|
|
90
75
|
if (!pathname.startsWith(SCOPE_PATH)) {
|
|
91
76
|
return false;
|
|
92
77
|
}
|
|
93
78
|
|
|
94
79
|
const parts = pathname.substring(SCOPE_PATH.length).split("/");
|
|
95
|
-
|
|
96
|
-
parts
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const kind = parts.shift();
|
|
100
|
-
if (kind !== "stream") {
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return (parts.length === 2 || parts.length === 3) &&
|
|
105
|
-
/^(?:0[xX])?[a-fA-F0-9]{40}$/.test(parts[0] || "") &&
|
|
106
|
-
isCanonicalStreamTopic(parts[1]) &&
|
|
107
|
-
isCanonicalStreamIndex(parts[2]);
|
|
80
|
+
return parts.length === 3 &&
|
|
81
|
+
parts[0] === "stream" &&
|
|
82
|
+
/^[a-fA-F0-9]{40}$/.test(parts[1]) &&
|
|
83
|
+
isCanonicalStreamTopic(parts[2]);
|
|
108
84
|
}
|
|
109
85
|
|
|
110
86
|
function isBzzUploadPath(pathname) {
|
|
@@ -138,21 +114,26 @@ function canonicalBzzResource(url) {
|
|
|
138
114
|
}
|
|
139
115
|
|
|
140
116
|
function canonicalRawResource(url) {
|
|
141
|
-
for (const [marker] of rawRouteMarkers()) {
|
|
117
|
+
for (const [marker, rawType] of rawRouteMarkers()) {
|
|
142
118
|
if (!url.pathname.startsWith(marker)) {
|
|
143
119
|
continue;
|
|
144
120
|
}
|
|
145
121
|
|
|
146
|
-
const
|
|
147
|
-
if (!
|
|
122
|
+
const encodedResource = url.pathname.substring(marker.length);
|
|
123
|
+
if (!encodedResource) {
|
|
148
124
|
return null;
|
|
149
125
|
}
|
|
150
126
|
|
|
127
|
+
let resource;
|
|
151
128
|
try {
|
|
152
|
-
|
|
129
|
+
resource = decodeURIComponent(encodedResource);
|
|
153
130
|
} catch (_) {
|
|
154
|
-
|
|
131
|
+
resource = encodedResource;
|
|
155
132
|
}
|
|
133
|
+
if (rawType === "hls-bytes" && !isSwarmReference(resource)) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return resource;
|
|
156
137
|
}
|
|
157
138
|
|
|
158
139
|
return null;
|
|
@@ -180,15 +161,6 @@ function canonicalFeedResource(url) {
|
|
|
180
161
|
return null;
|
|
181
162
|
}
|
|
182
163
|
|
|
183
|
-
function isCanonicalRequest(request) {
|
|
184
|
-
try {
|
|
185
|
-
const url = new URL(request.url);
|
|
186
|
-
return canonicalBzzResource(url) !== null || canonicalRawResource(url) !== null;
|
|
187
|
-
} catch (_) {
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
164
|
function isAppShellNavigation(request) {
|
|
193
165
|
const headerDestination = request.headers.get("Sec-Fetch-Dest") || "";
|
|
194
166
|
return request.method === "GET" &&
|
|
@@ -295,9 +267,6 @@ self.addEventListener("fetch", (event) => {
|
|
|
295
267
|
return;
|
|
296
268
|
}
|
|
297
269
|
|
|
298
|
-
// This worker is safe to mount in an npm application: requests outside the
|
|
299
|
-
// explicit weeb-3 routes remain entirely under the host app/browser's
|
|
300
|
-
// normal fetch and caching policy.
|
|
301
270
|
});
|
|
302
271
|
|
|
303
272
|
function clientInScope(client) {
|
|
@@ -382,10 +351,7 @@ async function firstReadyClient(candidates, requiredNetworkId) {
|
|
|
382
351
|
return [];
|
|
383
352
|
}
|
|
384
353
|
|
|
385
|
-
//
|
|
386
|
-
// most one probe timeout. Preserve the originating client's fast path and
|
|
387
|
-
// candidate priority; the accounting-sensitive operation itself is still
|
|
388
|
-
// sent exactly once by messageFirstClient.
|
|
354
|
+
// Probe candidates concurrently without redispatching work.
|
|
389
355
|
const probes = candidates.map((candidate) => clientWeeb3NetworkId(candidate));
|
|
390
356
|
if (await probes[0] === requiredNetworkId) {
|
|
391
357
|
return [candidates[0]];
|
|
@@ -413,12 +379,7 @@ async function requestClients(event, requestUrl, requiredNetworkId) {
|
|
|
413
379
|
)
|
|
414
380
|
);
|
|
415
381
|
|
|
416
|
-
//
|
|
417
|
-
// player, whether that page is the bundled shell or an arbitrary npm host.
|
|
418
|
-
// Dispatch those directly: the Rust bridge validates networkId before
|
|
419
|
-
// retrieval, while a redundant liveness round-trip here can false-timeout
|
|
420
|
-
// when a large WASM retrieval wave briefly occupies the browser thread.
|
|
421
|
-
// Nested clients retain the probed fallback below.
|
|
382
|
+
// Direct top-level HLS requests skip the redundant liveness probe.
|
|
422
383
|
if (
|
|
423
384
|
directHlsRequest &&
|
|
424
385
|
eventClient &&
|
|
@@ -436,9 +397,6 @@ async function requestClients(event, requestUrl, requiredNetworkId) {
|
|
|
436
397
|
const seen = new Set();
|
|
437
398
|
const requestReference = requestUrlObject ? bzzReferenceFromUrl(requestUrlObject) : "";
|
|
438
399
|
|
|
439
|
-
// Prefer the top-level context that originated the request. A nested BZZ
|
|
440
|
-
// site frame does not host the Rust runtime and must fall through to its
|
|
441
|
-
// active app-shell tab below.
|
|
442
400
|
if (eventClient && isTopLevelClient(eventClient) && clientInScope(eventClient)) {
|
|
443
401
|
pushUniqueClient(candidates, seen, eventClient);
|
|
444
402
|
}
|
|
@@ -532,10 +490,7 @@ function messageFirstClient(clients, message, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
|
532
490
|
});
|
|
533
491
|
}
|
|
534
492
|
|
|
535
|
-
//
|
|
536
|
-
// each request exactly once. A timeout merely detaches this response port;
|
|
537
|
-
// already-dispatched work is deliberately left to drain and is never replayed
|
|
538
|
-
// through another tab.
|
|
493
|
+
// Timeouts detach the port; dispatched accounting work is never replayed.
|
|
539
494
|
return messageClient(clients[0], message, timeoutMs);
|
|
540
495
|
}
|
|
541
496
|
|
|
@@ -638,16 +593,6 @@ function toUint8Array(body) {
|
|
|
638
593
|
return new Uint8Array();
|
|
639
594
|
}
|
|
640
595
|
|
|
641
|
-
function oneChunkResponseBody(body) {
|
|
642
|
-
const bytes = toUint8Array(body);
|
|
643
|
-
return new ReadableStream({
|
|
644
|
-
start(controller) {
|
|
645
|
-
controller.enqueue(bytes);
|
|
646
|
-
controller.close();
|
|
647
|
-
}
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
|
|
651
596
|
function responseHeaders(headerRows) {
|
|
652
597
|
const headers = new Headers();
|
|
653
598
|
for (const row of headerRows || []) {
|
|
@@ -774,7 +719,7 @@ async function forwardRequestToRust(request, event) {
|
|
|
774
719
|
return new Response(
|
|
775
720
|
request.method === "HEAD" || status === 304
|
|
776
721
|
? null
|
|
777
|
-
:
|
|
722
|
+
: toUint8Array(response.body),
|
|
778
723
|
{
|
|
779
724
|
status,
|
|
780
725
|
headers
|
|
@@ -788,12 +733,9 @@ async function forwardRequestToRust(request, event) {
|
|
|
788
733
|
}
|
|
789
734
|
|
|
790
735
|
function parseUploadRedundancyHeader(value) {
|
|
791
|
-
// Bee marks this header `omitempty`, so a present empty value has the same
|
|
792
|
-
// Medium default as an omitted header.
|
|
793
736
|
if (value === null || value === "") {
|
|
794
737
|
return 1;
|
|
795
738
|
}
|
|
796
|
-
// Bee parses an unsigned base-10 header, so reject Number()-only forms such as hex or exponents.
|
|
797
739
|
if (!/^[0-9]+$/.test(value)) {
|
|
798
740
|
return null;
|
|
799
741
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// Dynamic `import()` has no CSP-safe Web API callable directly from Wasm.
|
|
2
|
-
// Keep this irreducible bridge tiny; player policy and lifecycle live in Rust.
|
|
3
1
|
export async function loadHls() {
|
|
4
2
|
const module = await import("hls.js");
|
|
5
3
|
return module.default ?? module.Hls;
|