@bandeira-tech/b3nd-save 0.8.1
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/LICENSE +21 -0
- package/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +57 -0
- package/esm/byte-entity-shim.d.ts +47 -0
- package/esm/byte-entity-shim.d.ts.map +1 -0
- package/esm/byte-entity-shim.js +138 -0
- package/esm/clients/mod.d.ts +15 -0
- package/esm/clients/mod.d.ts.map +1 -0
- package/esm/clients/mod.js +14 -0
- package/esm/clients/save-client.d.ts +87 -0
- package/esm/clients/save-client.d.ts.map +1 -0
- package/esm/clients/save-client.js +174 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts +40 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.js +31 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts +30 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.js +70 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts +16 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.js +50 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts +235 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.js +619 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts +43 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.js +54 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts +47 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.js +134 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts +20 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.js +34 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts +46 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.js +131 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts +27 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.js +25 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts +59 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.js +188 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts +35 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.js +57 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts +117 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.js +125 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts +112 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.js +21 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts +35 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.js +106 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts +88 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.js +86 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts +83 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.js +115 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts +164 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.js +67 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts +99 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.js +190 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts +185 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.js +103 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts +58 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.js +64 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts +295 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.js +898 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts +167 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.js +5 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts +278 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts.map +1 -0
- package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.js +89 -0
- package/esm/dispatch.d.ts +35 -0
- package/esm/dispatch.d.ts.map +1 -0
- package/esm/dispatch.js +40 -0
- package/esm/elasticsearch/mod.d.ts +31 -0
- package/esm/elasticsearch/mod.d.ts.map +1 -0
- package/esm/elasticsearch/mod.js +8 -0
- package/esm/elasticsearch/store.d.ts +44 -0
- package/esm/elasticsearch/store.d.ts.map +1 -0
- package/esm/elasticsearch/store.js +213 -0
- package/esm/entity-store.d.ts +106 -0
- package/esm/entity-store.d.ts.map +1 -0
- package/esm/entity-store.js +46 -0
- package/esm/entity.d.ts +125 -0
- package/esm/entity.d.ts.map +1 -0
- package/esm/entity.js +66 -0
- package/esm/errors.d.ts +23 -0
- package/esm/errors.d.ts.map +1 -0
- package/esm/errors.js +25 -0
- package/esm/fs/mod.d.ts +28 -0
- package/esm/fs/mod.d.ts.map +1 -0
- package/esm/fs/mod.js +13 -0
- package/esm/fs/store.d.ts +45 -0
- package/esm/fs/store.d.ts.map +1 -0
- package/esm/fs/store.js +194 -0
- package/esm/indexeddb/mod.d.ts +9 -0
- package/esm/indexeddb/mod.d.ts.map +1 -0
- package/esm/indexeddb/mod.js +8 -0
- package/esm/indexeddb/store.d.ts +47 -0
- package/esm/indexeddb/store.d.ts.map +1 -0
- package/esm/indexeddb/store.js +299 -0
- package/esm/ipfs/mod.d.ts +24 -0
- package/esm/ipfs/mod.d.ts.map +1 -0
- package/esm/ipfs/mod.js +13 -0
- package/esm/ipfs/store.d.ts +42 -0
- package/esm/ipfs/store.d.ts.map +1 -0
- package/esm/ipfs/store.js +197 -0
- package/esm/localstorage/mod.d.ts +9 -0
- package/esm/localstorage/mod.d.ts.map +1 -0
- package/esm/localstorage/mod.js +8 -0
- package/esm/localstorage/store.d.ts +45 -0
- package/esm/localstorage/store.d.ts.map +1 -0
- package/esm/localstorage/store.js +147 -0
- package/esm/memory/mod.d.ts +12 -0
- package/esm/memory/mod.d.ts.map +1 -0
- package/esm/memory/mod.js +11 -0
- package/esm/memory/store.d.ts +73 -0
- package/esm/memory/store.d.ts.map +1 -0
- package/esm/memory/store.js +300 -0
- package/esm/mod.d.ts +36 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +31 -0
- package/esm/mongo/mod.d.ts +35 -0
- package/esm/mongo/mod.d.ts.map +1 -0
- package/esm/mongo/mod.js +8 -0
- package/esm/mongo/store.d.ts +42 -0
- package/esm/mongo/store.d.ts.map +1 -0
- package/esm/mongo/store.js +185 -0
- package/esm/package.json +3 -0
- package/esm/payload.d.ts +24 -0
- package/esm/payload.d.ts.map +1 -0
- package/esm/payload.js +30 -0
- package/esm/postgres/columns.d.ts +33 -0
- package/esm/postgres/columns.d.ts.map +1 -0
- package/esm/postgres/columns.js +51 -0
- package/esm/postgres/mod.d.ts +19 -0
- package/esm/postgres/mod.d.ts.map +1 -0
- package/esm/postgres/mod.js +9 -0
- package/esm/postgres/store.d.ts +75 -0
- package/esm/postgres/store.d.ts.map +1 -0
- package/esm/postgres/store.js +364 -0
- package/esm/read.d.ts +40 -0
- package/esm/read.d.ts.map +1 -0
- package/esm/read.js +67 -0
- package/esm/s3/mod.d.ts +23 -0
- package/esm/s3/mod.d.ts.map +1 -0
- package/esm/s3/mod.js +13 -0
- package/esm/s3/store.d.ts +46 -0
- package/esm/s3/store.d.ts.map +1 -0
- package/esm/s3/store.js +183 -0
- package/esm/sqlite/mod.d.ts +18 -0
- package/esm/sqlite/mod.d.ts.map +1 -0
- package/esm/sqlite/mod.js +8 -0
- package/esm/sqlite/schema.d.ts +10 -0
- package/esm/sqlite/schema.d.ts.map +1 -0
- package/esm/sqlite/schema.js +26 -0
- package/esm/sqlite/store.d.ts +42 -0
- package/esm/sqlite/store.d.ts.map +1 -0
- package/esm/sqlite/store.js +184 -0
- package/esm/types.d.ts +101 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/types.js +21 -0
- package/esm/url.d.ts +108 -0
- package/esm/url.d.ts.map +1 -0
- package/esm/url.js +151 -0
- package/package.json +93 -0
package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* FunctionalClient - A client that takes functions as config.
|
|
4
|
+
*
|
|
5
|
+
* Replaces createNode() for cases where you want to wire up
|
|
6
|
+
* custom behavior without class inheritance.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* A client that delegates each method to a config function.
|
|
10
|
+
*
|
|
11
|
+
* If a method is not provided, it returns a sensible default:
|
|
12
|
+
* - receive → { accepted: false, error: "not implemented" }
|
|
13
|
+
* - read → [{ success: false, error: "not implemented" }] per URI
|
|
14
|
+
* - status → { status: "healthy" }
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const client = new FunctionalClient({
|
|
19
|
+
* receive: async (msg) => backend.receive(msg),
|
|
20
|
+
* read: async (urls) => backend.read(urls),
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class FunctionalClient {
|
|
25
|
+
config;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.config = config;
|
|
28
|
+
}
|
|
29
|
+
receive(msgs) {
|
|
30
|
+
if (this.config.receive) {
|
|
31
|
+
return this.config.receive(msgs);
|
|
32
|
+
}
|
|
33
|
+
return Promise.resolve(msgs.map(() => ({ accepted: false, error: "not implemented" })));
|
|
34
|
+
}
|
|
35
|
+
read(urls) {
|
|
36
|
+
if (this.config.read) {
|
|
37
|
+
return this.config.read(urls);
|
|
38
|
+
}
|
|
39
|
+
// No read config → empty result (option-A absence semantics).
|
|
40
|
+
return Promise.resolve([]);
|
|
41
|
+
}
|
|
42
|
+
async *observe(urls, signal) {
|
|
43
|
+
if (this.config.observe) {
|
|
44
|
+
yield* this.config.observe(urls, signal);
|
|
45
|
+
}
|
|
46
|
+
// No observe config → empty stream (never yields)
|
|
47
|
+
}
|
|
48
|
+
status() {
|
|
49
|
+
if (this.config.status) {
|
|
50
|
+
return this.config.status();
|
|
51
|
+
}
|
|
52
|
+
return Promise.resolve({ status: "healthy" });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* URI pattern matching — shared by the rig (routing, reactions) and the
|
|
4
|
+
* observe emitter.
|
|
5
|
+
*
|
|
6
|
+
* Grammar (segments separated by `/`):
|
|
7
|
+
* - **literal** segments must match exactly.
|
|
8
|
+
* - `*` matches **exactly one** non-empty segment.
|
|
9
|
+
* - `**` matches **zero or more** remaining segments. Only valid as a
|
|
10
|
+
* complete final segment.
|
|
11
|
+
*
|
|
12
|
+
* Patterns compile to a closure once; the closure is called per URI.
|
|
13
|
+
* Three compile paths, picked at compile time:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Pure literal** (no metas) → `(uri) => uri === pattern`
|
|
16
|
+
* 2. **Trailing `**` only** → `(uri) => uri.startsWith(prefix)`
|
|
17
|
+
* 3. **Has a `*` somewhere** → compiled `RegExp`, matched via `test`.
|
|
18
|
+
*
|
|
19
|
+
* Captures are intentionally not exposed. Callers that need a segment
|
|
20
|
+
* value extract it from the URI directly (split on `/`, pick the index).
|
|
21
|
+
* Keeping the matcher bool-only collapses three callers — routing,
|
|
22
|
+
* observe, reactions — onto one fast path with no allocations.
|
|
23
|
+
*/
|
|
24
|
+
/** A compiled pattern: takes a URI, returns whether it matches. */
|
|
25
|
+
export type Matcher = (uri: string) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Compile a pattern string into a matcher closure.
|
|
28
|
+
*
|
|
29
|
+
* Throws `TypeError` on grammar violations:
|
|
30
|
+
* - `:param`-style segments (legacy; use `*` and extract from the URI).
|
|
31
|
+
* - `*` mixed into a segment with other chars (e.g. `abc*`, `*abc`).
|
|
32
|
+
* - `**` not as a complete final segment (e.g. `** /x`, `a/** b`).
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const m = compilePattern("mutable://**");
|
|
37
|
+
* m("mutable://users/alice"); // true
|
|
38
|
+
* m("hash://abc"); // false
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function compilePattern(pattern: string): Matcher;
|
|
42
|
+
/**
|
|
43
|
+
* One-shot matcher. Compiles the pattern every call — fine for ad-hoc
|
|
44
|
+
* use; prefer `compilePattern` for anything hot.
|
|
45
|
+
*/
|
|
46
|
+
export declare function matches(pattern: string, uri: string): boolean;
|
|
47
|
+
//# sourceMappingURL=match-pattern.d.ts.map
|
package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match-pattern.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,mEAAmE;AACnE,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAcvD;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7D"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* URI pattern matching — shared by the rig (routing, reactions) and the
|
|
4
|
+
* observe emitter.
|
|
5
|
+
*
|
|
6
|
+
* Grammar (segments separated by `/`):
|
|
7
|
+
* - **literal** segments must match exactly.
|
|
8
|
+
* - `*` matches **exactly one** non-empty segment.
|
|
9
|
+
* - `**` matches **zero or more** remaining segments. Only valid as a
|
|
10
|
+
* complete final segment.
|
|
11
|
+
*
|
|
12
|
+
* Patterns compile to a closure once; the closure is called per URI.
|
|
13
|
+
* Three compile paths, picked at compile time:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Pure literal** (no metas) → `(uri) => uri === pattern`
|
|
16
|
+
* 2. **Trailing `**` only** → `(uri) => uri.startsWith(prefix)`
|
|
17
|
+
* 3. **Has a `*` somewhere** → compiled `RegExp`, matched via `test`.
|
|
18
|
+
*
|
|
19
|
+
* Captures are intentionally not exposed. Callers that need a segment
|
|
20
|
+
* value extract it from the URI directly (split on `/`, pick the index).
|
|
21
|
+
* Keeping the matcher bool-only collapses three callers — routing,
|
|
22
|
+
* observe, reactions — onto one fast path with no allocations.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Compile a pattern string into a matcher closure.
|
|
26
|
+
*
|
|
27
|
+
* Throws `TypeError` on grammar violations:
|
|
28
|
+
* - `:param`-style segments (legacy; use `*` and extract from the URI).
|
|
29
|
+
* - `*` mixed into a segment with other chars (e.g. `abc*`, `*abc`).
|
|
30
|
+
* - `**` not as a complete final segment (e.g. `** /x`, `a/** b`).
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const m = compilePattern("mutable://**");
|
|
35
|
+
* m("mutable://users/alice"); // true
|
|
36
|
+
* m("hash://abc"); // false
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function compilePattern(pattern) {
|
|
40
|
+
const analysis = analyze(pattern);
|
|
41
|
+
if (analysis.kind === "literal") {
|
|
42
|
+
return (uri) => uri === pattern;
|
|
43
|
+
}
|
|
44
|
+
if (analysis.kind === "prefix") {
|
|
45
|
+
const prefix = analysis.prefix;
|
|
46
|
+
return (uri) => uri.startsWith(prefix);
|
|
47
|
+
}
|
|
48
|
+
const re = analysis.re;
|
|
49
|
+
return (uri) => re.test(uri);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* One-shot matcher. Compiles the pattern every call — fine for ad-hoc
|
|
53
|
+
* use; prefer `compilePattern` for anything hot.
|
|
54
|
+
*/
|
|
55
|
+
export function matches(pattern, uri) {
|
|
56
|
+
return compilePattern(pattern)(uri);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Walk the pattern once, segment-aware:
|
|
60
|
+
* - reject `:foo` segments (legacy capture syntax),
|
|
61
|
+
* - reject mixed-meta segments like `abc*` or `**x`,
|
|
62
|
+
* - detect a trailing `**` for the `startsWith` fast path,
|
|
63
|
+
* - detect any `*` to switch to the regex path.
|
|
64
|
+
*/
|
|
65
|
+
function analyze(pattern) {
|
|
66
|
+
const len = pattern.length;
|
|
67
|
+
let hasSingleStar = false;
|
|
68
|
+
let trailingDoubleStarAt = -1;
|
|
69
|
+
let segStart = 0;
|
|
70
|
+
for (let i = 0; i <= len; i++) {
|
|
71
|
+
if (i === len || pattern.charCodeAt(i) === 47 /* / */) {
|
|
72
|
+
const seg = pattern.slice(segStart, i);
|
|
73
|
+
classifySegment(seg, i === len);
|
|
74
|
+
if (seg === "**") {
|
|
75
|
+
if (i !== len) {
|
|
76
|
+
// `**` only valid as the last segment.
|
|
77
|
+
throw new TypeError(`pattern "${pattern}": "**" must be the final segment`);
|
|
78
|
+
}
|
|
79
|
+
// Position of the `**` in the original string (segStart).
|
|
80
|
+
trailingDoubleStarAt = segStart;
|
|
81
|
+
}
|
|
82
|
+
else if (seg === "*") {
|
|
83
|
+
hasSingleStar = true;
|
|
84
|
+
}
|
|
85
|
+
segStart = i + 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!hasSingleStar && trailingDoubleStarAt < 0) {
|
|
89
|
+
return { kind: "literal" };
|
|
90
|
+
}
|
|
91
|
+
if (!hasSingleStar && trailingDoubleStarAt >= 0) {
|
|
92
|
+
// Strip the trailing `**` (and the `/` before it, if any).
|
|
93
|
+
// segStart for `**` is the char *after* the leading `/`, so
|
|
94
|
+
// `pattern.slice(0, trailingDoubleStarAt)` keeps the trailing `/`.
|
|
95
|
+
return { kind: "prefix", prefix: pattern.slice(0, trailingDoubleStarAt) };
|
|
96
|
+
}
|
|
97
|
+
return { kind: "regex", re: toRegex(pattern) };
|
|
98
|
+
}
|
|
99
|
+
function classifySegment(seg, _isLast) {
|
|
100
|
+
if (seg === "*" || seg === "**" || !seg.includes("*")) {
|
|
101
|
+
if (seg.startsWith(":")) {
|
|
102
|
+
throw new TypeError(`pattern segment ":${seg.slice(1)}": ":param" syntax was removed; ` +
|
|
103
|
+
`use "*" and extract the value from the URI`);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Segment contains `*` mixed with other chars (e.g. `abc*`, `*x`, `a**b`).
|
|
108
|
+
throw new TypeError(`pattern segment "${seg}": "*" and "**" must be complete segments`);
|
|
109
|
+
}
|
|
110
|
+
/** Build a regex from a pattern containing `*` (and optionally trailing `**`). */
|
|
111
|
+
function toRegex(pattern) {
|
|
112
|
+
// Replace meta segments with placeholders that survive escaping, then
|
|
113
|
+
// escape, then swap placeholders for their regex equivalents.
|
|
114
|
+
//
|
|
115
|
+
// `*` (full segment) → `[^/]+` (one non-empty segment)
|
|
116
|
+
// `**` (trailing seg) → `.*` (zero or more remaining chars; the
|
|
117
|
+
// leading `/` before `**` is preserved
|
|
118
|
+
// by the surrounding pattern when the
|
|
119
|
+
// pattern has more than one segment,
|
|
120
|
+
// and absent when `**` is the whole
|
|
121
|
+
// pattern — both fall out naturally).
|
|
122
|
+
const ONE = "\x00ONE\x00";
|
|
123
|
+
const REST = "\x00REST\x00";
|
|
124
|
+
// Tokenize on `/` so we only swap full-segment metas.
|
|
125
|
+
const swapped = pattern
|
|
126
|
+
.split("/")
|
|
127
|
+
.map((seg) => seg === "*" ? ONE : seg === "**" ? REST : seg)
|
|
128
|
+
.join("/");
|
|
129
|
+
const escaped = swapped.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
130
|
+
const body = escaped
|
|
131
|
+
.replaceAll(ONE, "[^/]+")
|
|
132
|
+
.replaceAll(REST, ".*");
|
|
133
|
+
return new RegExp(`^${body}$`);
|
|
134
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Peer decorators — middleware that wraps a client while preserving the
|
|
4
|
+
* `ProtocolInterfaceNode` shape. Applied via `peer(client, { via: [decorator] })`.
|
|
5
|
+
*/
|
|
6
|
+
import type { PeerDecorator } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Swallow `receive()` errors and report them as accepted.
|
|
9
|
+
*
|
|
10
|
+
* Use for best-effort push: when you want a one-peer failure to be
|
|
11
|
+
* logged and otherwise ignored rather than aborting the whole fan-out.
|
|
12
|
+
* Every other method (read, observe, status) is passed through
|
|
13
|
+
* unchanged so bridges and observers behave normally.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* peer(remoteClient, { via: [bestEffort] })
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const bestEffort: PeerDecorator;
|
|
20
|
+
//# sourceMappingURL=decorators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,aAiBvB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Peer decorators — middleware that wraps a client while preserving the
|
|
4
|
+
* `ProtocolInterfaceNode` shape. Applied via `peer(client, { via: [decorator] })`.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Swallow `receive()` errors and report them as accepted.
|
|
8
|
+
*
|
|
9
|
+
* Use for best-effort push: when you want a one-peer failure to be
|
|
10
|
+
* logged and otherwise ignored rather than aborting the whole fan-out.
|
|
11
|
+
* Every other method (read, observe, status) is passed through
|
|
12
|
+
* unchanged so bridges and observers behave normally.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* peer(remoteClient, { via: [bestEffort] })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export const bestEffort = (client) => ({
|
|
19
|
+
async receive(msgs) {
|
|
20
|
+
try {
|
|
21
|
+
return await client.receive(msgs);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
25
|
+
console.warn(`[peer] best-effort receive failed: ${msg}`);
|
|
26
|
+
return msgs.map(() => ({ accepted: true }));
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
read: (urls) => client.read(urls),
|
|
30
|
+
observe: (urls, signal) => client.observe(urls, signal),
|
|
31
|
+
// bestEffort decorator preserves the underlying client's observe
|
|
32
|
+
// and read shape; the only enhancement is non-fatal receive.
|
|
33
|
+
status: () => client.status(),
|
|
34
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* `network(target, peers, policies?, opts?)` — the participant verb.
|
|
4
|
+
*
|
|
5
|
+
* Subscribes each peer's observe stream, passes events through the
|
|
6
|
+
* (optional) chain of `Policy.receive` hooks, and forwards yielded
|
|
7
|
+
* events into `target.receive`. Returns an async unbind that aborts
|
|
8
|
+
* every peer loop and awaits clean teardown.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { network, peer, pathVector } from "@bandeira-tech/b3nd-core/network";
|
|
12
|
+
*
|
|
13
|
+
* const unbind = network(rig, peers); // no policies
|
|
14
|
+
* const unbind = network(rig, peers, [myPolicy]); // one policy
|
|
15
|
+
* const unbind = network(rig, peers, [filter, tellAndRead], { // multiple, chained
|
|
16
|
+
* pattern: "mutable://chat/**",
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* await unbind();
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `network()` is not a `ProtocolInterfaceNode`. Passing a peer list to
|
|
23
|
+
* a strategy factory (`flood(peers)`, `pathVector(peers)`) is how you
|
|
24
|
+
* build the remote-client shape for `connection()`.
|
|
25
|
+
*/
|
|
26
|
+
import type { ProtocolInterfaceNode } from "../types/types.js";
|
|
27
|
+
import type { NetworkOptions, Peer, Policy } from "./types.js";
|
|
28
|
+
/**
|
|
29
|
+
* Wire peers into a target's `receive` pipeline.
|
|
30
|
+
*
|
|
31
|
+
* Returns an async unbind; calling it aborts each peer's observe signal
|
|
32
|
+
* and awaits the per-peer loops so teardown is resource-sanitizer-clean.
|
|
33
|
+
* Idempotent — calling twice is a no-op.
|
|
34
|
+
*/
|
|
35
|
+
export declare function network(target: Pick<ProtocolInterfaceNode, "receive">, peers: Peer[], policies?: Policy[], opts?: NetworkOptions): () => Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Shared peer-list validation. Exported for strategy factories that
|
|
38
|
+
* want the same uniqueness / non-empty guarantees.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export declare function validatePeers(peers: Peer[]): {
|
|
43
|
+
originId: string;
|
|
44
|
+
peers: readonly Peer[];
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAU,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAc,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE3E;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,CAAC,EAC9C,KAAK,EAAE,IAAI,EAAE,EACb,QAAQ,GAAE,MAAM,EAAO,EACvB,IAAI,GAAE,cAAmB,GACxB,MAAM,OAAO,CAAC,IAAI,CAAC,CAiBrB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,IAAI,EAAE,GACZ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;CAAE,CAe9C"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* `network(target, peers, policies?, opts?)` — the participant verb.
|
|
4
|
+
*
|
|
5
|
+
* Subscribes each peer's observe stream, passes events through the
|
|
6
|
+
* (optional) chain of `Policy.receive` hooks, and forwards yielded
|
|
7
|
+
* events into `target.receive`. Returns an async unbind that aborts
|
|
8
|
+
* every peer loop and awaits clean teardown.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { network, peer, pathVector } from "@bandeira-tech/b3nd-core/network";
|
|
12
|
+
*
|
|
13
|
+
* const unbind = network(rig, peers); // no policies
|
|
14
|
+
* const unbind = network(rig, peers, [myPolicy]); // one policy
|
|
15
|
+
* const unbind = network(rig, peers, [filter, tellAndRead], { // multiple, chained
|
|
16
|
+
* pattern: "mutable://chat/**",
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* await unbind();
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `network()` is not a `ProtocolInterfaceNode`. Passing a peer list to
|
|
23
|
+
* a strategy factory (`flood(peers)`, `pathVector(peers)`) is how you
|
|
24
|
+
* build the remote-client shape for `connection()`.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Wire peers into a target's `receive` pipeline.
|
|
28
|
+
*
|
|
29
|
+
* Returns an async unbind; calling it aborts each peer's observe signal
|
|
30
|
+
* and awaits the per-peer loops so teardown is resource-sanitizer-clean.
|
|
31
|
+
* Idempotent — calling twice is a no-op.
|
|
32
|
+
*/
|
|
33
|
+
export function network(target, peers, policies = [], opts = {}) {
|
|
34
|
+
const { originId, peers: frozenPeers } = validatePeers(peers);
|
|
35
|
+
const pattern = opts.pattern ?? "**";
|
|
36
|
+
const onError = opts.onError ?? (() => { });
|
|
37
|
+
const ac = new AbortController();
|
|
38
|
+
const tasks = frozenPeers.map((peer) => runPeer(peer, policies, originId, target, pattern, ac.signal, onError));
|
|
39
|
+
let unbound = false;
|
|
40
|
+
return async () => {
|
|
41
|
+
if (unbound)
|
|
42
|
+
return;
|
|
43
|
+
unbound = true;
|
|
44
|
+
ac.abort();
|
|
45
|
+
await Promise.allSettled(tasks);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Shared peer-list validation. Exported for strategy factories that
|
|
50
|
+
* want the same uniqueness / non-empty guarantees.
|
|
51
|
+
*
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export function validatePeers(peers) {
|
|
55
|
+
if (!peers || peers.length === 0) {
|
|
56
|
+
throw new Error("peers[] must be non-empty");
|
|
57
|
+
}
|
|
58
|
+
const ids = new Set();
|
|
59
|
+
for (const p of peers) {
|
|
60
|
+
if (ids.has(p.id)) {
|
|
61
|
+
throw new Error(`duplicate peer id "${p.id}"`);
|
|
62
|
+
}
|
|
63
|
+
ids.add(p.id);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
originId: `net-${crypto.randomUUID()}`,
|
|
67
|
+
peers: Object.freeze([...peers]),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// ── Internals: the bridge ─────────────────────────────────────────────
|
|
71
|
+
/**
|
|
72
|
+
* One peer's subscription loop. Kept as a separate function (not an
|
|
73
|
+
* inline IIFE) so error stacks identify the misbehaving peer.
|
|
74
|
+
*/
|
|
75
|
+
async function runPeer(peer, policies, originId, target, pattern, signal, onError) {
|
|
76
|
+
const ctx = { originId, source: peer };
|
|
77
|
+
const hooks = policies
|
|
78
|
+
.map((p) => p.receive?.bind(p))
|
|
79
|
+
.filter((r) => r !== undefined);
|
|
80
|
+
try {
|
|
81
|
+
for await (const uris of peer.client.observe([pattern], signal)) {
|
|
82
|
+
if (signal.aborted)
|
|
83
|
+
break;
|
|
84
|
+
// INV bundles: the observe event lists uris that changed. Pull
|
|
85
|
+
// the current state from the peer for each so policies see
|
|
86
|
+
// Outputs with the content attached.
|
|
87
|
+
for (const noteUri of uris) {
|
|
88
|
+
if (signal.aborted)
|
|
89
|
+
break;
|
|
90
|
+
const fetched = await peer.client.read([noteUri]);
|
|
91
|
+
for (const ev of fetched) {
|
|
92
|
+
for await (const out of foldReceive(ev, hooks, peer, ctx)) {
|
|
93
|
+
if (signal.aborted)
|
|
94
|
+
break;
|
|
95
|
+
await forward(target, out, onError, peer.id);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
onError(toError(err), { peerId: peer.id });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Fold `hooks` over `ev`: apply `hooks[0]` to `ev`, then `hooks[1]` to
|
|
107
|
+
* each event yielded, and so on. The result is one merged stream of
|
|
108
|
+
* Outputs the target should receive.
|
|
109
|
+
*/
|
|
110
|
+
async function* foldReceive(ev, hooks, source, ctx) {
|
|
111
|
+
if (hooks.length === 0) {
|
|
112
|
+
yield ev;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const [first, ...rest] = hooks;
|
|
116
|
+
for await (const out of first(ev, source, ctx)) {
|
|
117
|
+
yield* foldReceive(out, rest, source, ctx);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Forward one Output into the target's `receive`. Swallows errors via `onError`. */
|
|
121
|
+
async function forward(target, ev, onError, peerId) {
|
|
122
|
+
try {
|
|
123
|
+
await target.receive([ev]);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
onError(toError(err), { peerId });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function toError(e) {
|
|
130
|
+
return e instanceof Error ? e : new Error(String(e));
|
|
131
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* `peer()` — construct a Peer from a client, optionally applying decorators
|
|
4
|
+
* and pinning an explicit id.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProtocolInterfaceNode } from "../types/types.js";
|
|
7
|
+
import type { Peer, PeerDecorator } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Create a Peer from a client.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Anonymous peer — id auto-assigned at runtime
|
|
14
|
+
* peer(remoteClient)
|
|
15
|
+
*
|
|
16
|
+
* // Protocol with path-vector loop avoidance — id matches the peer's pubkey
|
|
17
|
+
* peer(client, { id: peerPubkeyHex })
|
|
18
|
+
*
|
|
19
|
+
* // Stack middleware
|
|
20
|
+
* peer(client, { via: [bestEffort, rateLimited(10)] })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function peer(client: ProtocolInterfaceNode, opts?: {
|
|
24
|
+
id?: string;
|
|
25
|
+
via?: PeerDecorator[];
|
|
26
|
+
}): Peer;
|
|
27
|
+
//# sourceMappingURL=peer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAClB,MAAM,EAAE,qBAAqB,EAC7B,IAAI,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,aAAa,EAAE,CAAA;CAAO,GAChD,IAAI,CAON"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* `peer()` — construct a Peer from a client, optionally applying decorators
|
|
4
|
+
* and pinning an explicit id.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Create a Peer from a client.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Anonymous peer — id auto-assigned at runtime
|
|
12
|
+
* peer(remoteClient)
|
|
13
|
+
*
|
|
14
|
+
* // Protocol with path-vector loop avoidance — id matches the peer's pubkey
|
|
15
|
+
* peer(client, { id: peerPubkeyHex })
|
|
16
|
+
*
|
|
17
|
+
* // Stack middleware
|
|
18
|
+
* peer(client, { via: [bestEffort, rateLimited(10)] })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function peer(client, opts = {}) {
|
|
22
|
+
const id = opts.id ?? `peer-${crypto.randomUUID()}`;
|
|
23
|
+
const decorated = (opts.via ?? []).reduce((c, decorator) => decorator(c), client);
|
|
24
|
+
return { id, client: decorated };
|
|
25
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* `flood(peers)` — the baseline remote-client strategy.
|
|
4
|
+
*
|
|
5
|
+
* Returns a `ProtocolInterfaceNode` that:
|
|
6
|
+
* - **receive**: fans every write out to every peer in parallel
|
|
7
|
+
* - **read**: tries peers in order and returns the first successful hit
|
|
8
|
+
* - **observe**: merges every peer's observe stream into one iterator
|
|
9
|
+
* - **status**: aggregates peer health (healthy / degraded / unhealthy)
|
|
10
|
+
*
|
|
11
|
+
* Use as a rig connection:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { connection, Rig } from "@bandeira-tech/b3nd-core";
|
|
15
|
+
* import { flood, peer } from "@bandeira-tech/b3nd-core/network";
|
|
16
|
+
*
|
|
17
|
+
* const peers = connection(flood([peer(remoteClient)]), ["**"]);
|
|
18
|
+
* const rig = new Rig({
|
|
19
|
+
* routes: { receive: [peers], read: [peers], observe: [peers] },
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* For bidirectional signed meshes that need loop avoidance, use
|
|
24
|
+
* `pathVector(peers)` instead — same shape, plus a signer-chain filter
|
|
25
|
+
* on outbound.
|
|
26
|
+
*
|
|
27
|
+
* ## Error handling
|
|
28
|
+
*
|
|
29
|
+
* - `receive` propagates transport-level failures — one peer rejecting
|
|
30
|
+
* aborts the fan-out. Wrap individual peers with the `bestEffort`
|
|
31
|
+
* decorator if you want per-peer failures to be non-fatal.
|
|
32
|
+
* - `read` falls through: a failing peer is skipped, and if no peer
|
|
33
|
+
* returns a hit the result is a `not-found` per input URI.
|
|
34
|
+
* - `observe` silently drops a peer whose stream throws (the merged
|
|
35
|
+
* stream keeps flowing from the remaining peers). This is
|
|
36
|
+
* intentional — `flood` is a one-shot PIN with no `onError` hook.
|
|
37
|
+
* For observability over the inbound side, use `network()`, which
|
|
38
|
+
* accepts an `onError` callback and reports per-peer failures.
|
|
39
|
+
* - `status` aggregates; individual unhealthy peers degrade the
|
|
40
|
+
* overall status rather than throwing.
|
|
41
|
+
*/
|
|
42
|
+
import type { Output, ProtocolInterfaceNode } from "../../types/types.js";
|
|
43
|
+
import type { Peer } from "../types.js";
|
|
44
|
+
/**
|
|
45
|
+
* Build a flood PIN from peers. Peers must have unique ids and the list
|
|
46
|
+
* must be non-empty.
|
|
47
|
+
*/
|
|
48
|
+
export declare function flood(peers: Peer[]): ProtocolInterfaceNode;
|
|
49
|
+
/**
|
|
50
|
+
* Internal shared implementation used by `flood`, `pathVector`, and
|
|
51
|
+
* `tellAndRead.outbound`. The `transform` rewrites the per-peer
|
|
52
|
+
* outbound batch: return `msgs` unchanged to flood as-is, return a
|
|
53
|
+
* subset to filter, return rewritten outputs to change what the peer
|
|
54
|
+
* receives, or return `[]` to skip the peer entirely.
|
|
55
|
+
*
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export declare function floodImpl(originId: string, peers: readonly Peer[], transform: (msgs: Output[], peer: Peer) => Output[]): ProtocolInterfaceNode;
|
|
59
|
+
//# sourceMappingURL=flood.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flood.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EAGtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,qBAAqB,CAG1D;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,KAAK,MAAM,EAAE,GAClD,qBAAqB,CAsHvB"}
|