@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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/esm/_dnt.shims.d.ts +2 -0
  3. package/esm/_dnt.shims.d.ts.map +1 -0
  4. package/esm/_dnt.shims.js +57 -0
  5. package/esm/byte-entity-shim.d.ts +47 -0
  6. package/esm/byte-entity-shim.d.ts.map +1 -0
  7. package/esm/byte-entity-shim.js +138 -0
  8. package/esm/clients/mod.d.ts +15 -0
  9. package/esm/clients/mod.d.ts.map +1 -0
  10. package/esm/clients/mod.js +14 -0
  11. package/esm/clients/save-client.d.ts +87 -0
  12. package/esm/clients/save-client.d.ts.map +1 -0
  13. package/esm/clients/save-client.js +174 -0
  14. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts +40 -0
  15. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts.map +1 -0
  16. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.js +31 -0
  17. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts +30 -0
  18. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.d.ts.map +1 -0
  19. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/client-console/client.js +70 -0
  20. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts +16 -0
  21. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.d.ts.map +1 -0
  22. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encoding/encoding.js +50 -0
  23. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts +235 -0
  24. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts.map +1 -0
  25. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.js +619 -0
  26. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts +43 -0
  27. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.d.ts.map +1 -0
  28. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/functional-client/functional-client.js +54 -0
  29. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts +47 -0
  30. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.d.ts.map +1 -0
  31. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/match-pattern/match-pattern.js +134 -0
  32. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts +20 -0
  33. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.d.ts.map +1 -0
  34. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/decorators.js +34 -0
  35. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts +46 -0
  36. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.d.ts.map +1 -0
  37. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/network.js +131 -0
  38. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts +27 -0
  39. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.d.ts.map +1 -0
  40. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/peer.js +25 -0
  41. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts +59 -0
  42. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.d.ts.map +1 -0
  43. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/flood.js +188 -0
  44. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts +35 -0
  45. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts.map +1 -0
  46. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.js +57 -0
  47. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts +117 -0
  48. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.d.ts.map +1 -0
  49. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/tell-and-read.js +125 -0
  50. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts +112 -0
  51. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.d.ts.map +1 -0
  52. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/types.js +21 -0
  53. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts +35 -0
  54. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.d.ts.map +1 -0
  55. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.js +106 -0
  56. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts +88 -0
  57. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts.map +1 -0
  58. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.js +86 -0
  59. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts +83 -0
  60. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.d.ts.map +1 -0
  61. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.js +115 -0
  62. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts +164 -0
  63. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.d.ts.map +1 -0
  64. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/hooks.js +67 -0
  65. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts +99 -0
  66. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.d.ts.map +1 -0
  67. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/identity.js +190 -0
  68. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts +185 -0
  69. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.d.ts.map +1 -0
  70. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/operation-handle.js +103 -0
  71. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts +58 -0
  72. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.d.ts.map +1 -0
  73. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/reactions.js +64 -0
  74. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts +295 -0
  75. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts.map +1 -0
  76. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.js +898 -0
  77. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts +167 -0
  78. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts.map +1 -0
  79. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.js +5 -0
  80. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts +278 -0
  81. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts.map +1 -0
  82. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.js +89 -0
  83. package/esm/dispatch.d.ts +35 -0
  84. package/esm/dispatch.d.ts.map +1 -0
  85. package/esm/dispatch.js +40 -0
  86. package/esm/elasticsearch/mod.d.ts +31 -0
  87. package/esm/elasticsearch/mod.d.ts.map +1 -0
  88. package/esm/elasticsearch/mod.js +8 -0
  89. package/esm/elasticsearch/store.d.ts +44 -0
  90. package/esm/elasticsearch/store.d.ts.map +1 -0
  91. package/esm/elasticsearch/store.js +213 -0
  92. package/esm/entity-store.d.ts +106 -0
  93. package/esm/entity-store.d.ts.map +1 -0
  94. package/esm/entity-store.js +46 -0
  95. package/esm/entity.d.ts +125 -0
  96. package/esm/entity.d.ts.map +1 -0
  97. package/esm/entity.js +66 -0
  98. package/esm/errors.d.ts +23 -0
  99. package/esm/errors.d.ts.map +1 -0
  100. package/esm/errors.js +25 -0
  101. package/esm/fs/mod.d.ts +28 -0
  102. package/esm/fs/mod.d.ts.map +1 -0
  103. package/esm/fs/mod.js +13 -0
  104. package/esm/fs/store.d.ts +45 -0
  105. package/esm/fs/store.d.ts.map +1 -0
  106. package/esm/fs/store.js +194 -0
  107. package/esm/indexeddb/mod.d.ts +9 -0
  108. package/esm/indexeddb/mod.d.ts.map +1 -0
  109. package/esm/indexeddb/mod.js +8 -0
  110. package/esm/indexeddb/store.d.ts +47 -0
  111. package/esm/indexeddb/store.d.ts.map +1 -0
  112. package/esm/indexeddb/store.js +299 -0
  113. package/esm/ipfs/mod.d.ts +24 -0
  114. package/esm/ipfs/mod.d.ts.map +1 -0
  115. package/esm/ipfs/mod.js +13 -0
  116. package/esm/ipfs/store.d.ts +42 -0
  117. package/esm/ipfs/store.d.ts.map +1 -0
  118. package/esm/ipfs/store.js +197 -0
  119. package/esm/localstorage/mod.d.ts +9 -0
  120. package/esm/localstorage/mod.d.ts.map +1 -0
  121. package/esm/localstorage/mod.js +8 -0
  122. package/esm/localstorage/store.d.ts +45 -0
  123. package/esm/localstorage/store.d.ts.map +1 -0
  124. package/esm/localstorage/store.js +147 -0
  125. package/esm/memory/mod.d.ts +12 -0
  126. package/esm/memory/mod.d.ts.map +1 -0
  127. package/esm/memory/mod.js +11 -0
  128. package/esm/memory/store.d.ts +73 -0
  129. package/esm/memory/store.d.ts.map +1 -0
  130. package/esm/memory/store.js +300 -0
  131. package/esm/mod.d.ts +36 -0
  132. package/esm/mod.d.ts.map +1 -0
  133. package/esm/mod.js +31 -0
  134. package/esm/mongo/mod.d.ts +35 -0
  135. package/esm/mongo/mod.d.ts.map +1 -0
  136. package/esm/mongo/mod.js +8 -0
  137. package/esm/mongo/store.d.ts +42 -0
  138. package/esm/mongo/store.d.ts.map +1 -0
  139. package/esm/mongo/store.js +185 -0
  140. package/esm/package.json +3 -0
  141. package/esm/payload.d.ts +24 -0
  142. package/esm/payload.d.ts.map +1 -0
  143. package/esm/payload.js +30 -0
  144. package/esm/postgres/columns.d.ts +33 -0
  145. package/esm/postgres/columns.d.ts.map +1 -0
  146. package/esm/postgres/columns.js +51 -0
  147. package/esm/postgres/mod.d.ts +19 -0
  148. package/esm/postgres/mod.d.ts.map +1 -0
  149. package/esm/postgres/mod.js +9 -0
  150. package/esm/postgres/store.d.ts +75 -0
  151. package/esm/postgres/store.d.ts.map +1 -0
  152. package/esm/postgres/store.js +364 -0
  153. package/esm/read.d.ts +40 -0
  154. package/esm/read.d.ts.map +1 -0
  155. package/esm/read.js +67 -0
  156. package/esm/s3/mod.d.ts +23 -0
  157. package/esm/s3/mod.d.ts.map +1 -0
  158. package/esm/s3/mod.js +13 -0
  159. package/esm/s3/store.d.ts +46 -0
  160. package/esm/s3/store.d.ts.map +1 -0
  161. package/esm/s3/store.js +183 -0
  162. package/esm/sqlite/mod.d.ts +18 -0
  163. package/esm/sqlite/mod.d.ts.map +1 -0
  164. package/esm/sqlite/mod.js +8 -0
  165. package/esm/sqlite/schema.d.ts +10 -0
  166. package/esm/sqlite/schema.d.ts.map +1 -0
  167. package/esm/sqlite/schema.js +26 -0
  168. package/esm/sqlite/store.d.ts +42 -0
  169. package/esm/sqlite/store.d.ts.map +1 -0
  170. package/esm/sqlite/store.js +184 -0
  171. package/esm/types.d.ts +101 -0
  172. package/esm/types.d.ts.map +1 -0
  173. package/esm/types.js +21 -0
  174. package/esm/url.d.ts +108 -0
  175. package/esm/url.d.ts.map +1 -0
  176. package/esm/url.js +151 -0
  177. package/package.json +93 -0
@@ -0,0 +1,35 @@
1
+ export type ObserveListener = (uri: string, data: unknown) => void;
2
+ /**
3
+ * Base class providing a write/delete listener bus and an async iterator
4
+ * for observing URI-pattern changes.
5
+ *
6
+ * Subclasses call `_emit(uri, data)` on successful writes and
7
+ * `_emitDeletes(uris)` on successful deletes. The emitter ignores
8
+ * `data` for INV-style notifications — observers receive only the
9
+ * uri and read it themselves.
10
+ */
11
+ export declare class ObserveEmitter {
12
+ protected _listeners: Set<ObserveListener>;
13
+ /**
14
+ * Notify all listeners of a URI change. `data` is accepted for
15
+ * compatibility with subclasses that may reuse the listener bus,
16
+ * but it is not surfaced to observe iterators.
17
+ */
18
+ protected _emit(uri: string, data: unknown): void;
19
+ /** Notify all listeners that each URI was deleted. */
20
+ protected _emitDeletes(uris: readonly string[]): void;
21
+ /**
22
+ * Async iterator yielding `readonly string[]` batches of uris that
23
+ * changed under any input pattern. Runs until `signal` aborts.
24
+ *
25
+ * Default emission yields a singleton batch per matching change;
26
+ * subclasses with cheap batching can override to coalesce.
27
+ *
28
+ * The listener stays registered for the lifetime of the iteration;
29
+ * events fired while the consumer is processing a yielded value are
30
+ * buffered in a per-iterator queue so nothing is dropped across the
31
+ * yield boundary.
32
+ */
33
+ observe(urls: string[], signal: AbortSignal): AsyncIterable<readonly string[]>;
34
+ }
35
+ //# sourceMappingURL=observe-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe-emitter.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/observe-emitter/observe-emitter.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,eAAe,GAAG,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,KACV,IAAI,CAAC;AAEV;;;;;;;;GAQG;AACH,qBAAa,cAAc;IACzB,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,eAAe,CAAC,CAA8B;IAExE;;;;OAIG;IACH,SAAS,CAAC,KAAK,CACb,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,GACZ,IAAI;IAUP,sDAAsD;IACtD,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAIrD;;;;;;;;;;;OAWG;IACI,OAAO,CACZ,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,WAAW,GAClB,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC;CA2CpC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @module
3
+ * ObserveEmitter — the shared listener + async-iterator machinery
4
+ * `ProtocolInterfaceNode` implementations use to expose `observe()`.
5
+ *
6
+ * Observe is INV-style notification: each successful write or delete
7
+ * yields a `readonly string[]` — the batch of concrete uris that
8
+ * fired. The default emitter sends one uri per yield; backends with
9
+ * cheap batching can send several. A single change matching several
10
+ * input patterns yields once (not once per matching pattern); callers
11
+ * who need to know which of their patterns matched re-run the match
12
+ * locally, which is cheap and keeps the stream minimal.
13
+ *
14
+ * `observe(locators, signal)` accepts locators as opaque strings and
15
+ * matches them as segment-globs against emitted uris. The shared glob
16
+ * grammar (`*` for one segment, `**` for the rest) applies. Any
17
+ * normalization (e.g. stripping request-time directives before matching)
18
+ * is the executing client's responsibility.
19
+ */
20
+ import { compilePattern, } from "../match-pattern/match-pattern.js";
21
+ /**
22
+ * Base class providing a write/delete listener bus and an async iterator
23
+ * for observing URI-pattern changes.
24
+ *
25
+ * Subclasses call `_emit(uri, data)` on successful writes and
26
+ * `_emitDeletes(uris)` on successful deletes. The emitter ignores
27
+ * `data` for INV-style notifications — observers receive only the
28
+ * uri and read it themselves.
29
+ */
30
+ export class ObserveEmitter {
31
+ _listeners = new Set();
32
+ /**
33
+ * Notify all listeners of a URI change. `data` is accepted for
34
+ * compatibility with subclasses that may reuse the listener bus,
35
+ * but it is not surfaced to observe iterators.
36
+ */
37
+ _emit(uri, data) {
38
+ for (const listener of this._listeners) {
39
+ try {
40
+ listener(uri, data);
41
+ }
42
+ catch {
43
+ // Listener errors must never break the emitter.
44
+ }
45
+ }
46
+ }
47
+ /** Notify all listeners that each URI was deleted. */
48
+ _emitDeletes(uris) {
49
+ for (const uri of uris)
50
+ this._emit(uri, null);
51
+ }
52
+ /**
53
+ * Async iterator yielding `readonly string[]` batches of uris that
54
+ * changed under any input pattern. Runs until `signal` aborts.
55
+ *
56
+ * Default emission yields a singleton batch per matching change;
57
+ * subclasses with cheap batching can override to coalesce.
58
+ *
59
+ * The listener stays registered for the lifetime of the iteration;
60
+ * events fired while the consumer is processing a yielded value are
61
+ * buffered in a per-iterator queue so nothing is dropped across the
62
+ * yield boundary.
63
+ */
64
+ async *observe(urls, signal) {
65
+ const matchers = urls.map(compilePattern);
66
+ const queue = [];
67
+ let wake = null;
68
+ const listener = (uri, _data) => {
69
+ for (let i = 0; i < matchers.length; i++) {
70
+ if (matchers[i](uri)) {
71
+ queue.push([uri]);
72
+ const w = wake;
73
+ if (w) {
74
+ wake = null;
75
+ w();
76
+ }
77
+ return;
78
+ }
79
+ }
80
+ };
81
+ const onAbort = () => {
82
+ const w = wake;
83
+ if (w) {
84
+ wake = null;
85
+ w();
86
+ }
87
+ };
88
+ this._listeners.add(listener);
89
+ signal.addEventListener("abort", onAbort, { once: true });
90
+ try {
91
+ while (true) {
92
+ while (queue.length > 0)
93
+ yield queue.shift();
94
+ if (signal.aborted)
95
+ return;
96
+ await new Promise((resolve) => {
97
+ wake = resolve;
98
+ });
99
+ }
100
+ }
101
+ finally {
102
+ this._listeners.delete(listener);
103
+ signal.removeEventListener("abort", onAbort);
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @module
3
+ * Connection — a client bound to a URI pattern list.
4
+ *
5
+ * A `Connection` wraps a `ProtocolInterfaceNode` with a set of URI
6
+ * filter patterns. Connections are bound into the rig's `routes`
7
+ * config (`receive`, `read`, `observe`) — each route gets its own
8
+ * ordered list of connections.
9
+ *
10
+ * The same connection value can be referenced from multiple routes
11
+ * (when one client serves writes, reads, and observes with the same
12
+ * filter); a different filter for a different op means a separate
13
+ * `connection(...)` call.
14
+ *
15
+ * Pattern syntax (same as observe and reactions):
16
+ * - `*` matches exactly one non-empty segment
17
+ * - `**` matches zero or more remaining segments (final segment only)
18
+ * - Literal segments must match exactly
19
+ *
20
+ * @example A single client serving all three ops
21
+ * ```ts
22
+ * import { connection, Rig } from "@bandeira-tech/b3nd-core";
23
+ *
24
+ * const node = connection(httpClient, ["mutable://**", "hash://**"]);
25
+ *
26
+ * const rig = new Rig({
27
+ * routes: {
28
+ * receive: [node],
29
+ * read: [node],
30
+ * observe: [node],
31
+ * },
32
+ * });
33
+ * ```
34
+ *
35
+ * @example Asymmetric topology — write-mirror, read-cache, narrow observe
36
+ * ```ts
37
+ * const primary = connection(httpClient, ["mutable://**", "hash://**"], { id: "primary" });
38
+ * const mirror = connection(pgClient, ["mutable://**", "hash://**"], { id: "mirror" });
39
+ * const cache = connection(redisClient, ["mutable://accounts/**"], { id: "cache" });
40
+ * const obsNarrow = connection(httpClient, ["mutable://**"], { id: "primary-obs" });
41
+ *
42
+ * const rig = new Rig({
43
+ * routes: {
44
+ * receive: [primary, mirror], // broadcast both
45
+ * read: [cache, primary], // try cache first, then primary
46
+ * observe: [obsNarrow], // narrow namespace, primary only
47
+ * },
48
+ * });
49
+ * ```
50
+ */
51
+ import type { ProtocolInterfaceNode } from "../types/types.js";
52
+ /** Optional configuration for a connection. */
53
+ export interface ConnectionOptions {
54
+ /**
55
+ * Stable identifier for this connection. Surfaces in
56
+ * `route:success`/`route:error` events on the operation handle and
57
+ * lets operators tell replicas apart in observability data.
58
+ * Auto-generated as `conn-{N}` (registration order) when omitted.
59
+ */
60
+ id?: string;
61
+ }
62
+ /** A connection: a client wrapped with a URI pattern list. */
63
+ export interface Connection {
64
+ /** Stable identifier (provided or auto-generated). */
65
+ readonly id: string;
66
+ /** The underlying client. */
67
+ readonly client: ProtocolInterfaceNode;
68
+ /**
69
+ * The raw patterns — serializable for wire protocols.
70
+ * Send this to a remote node so it knows what to push.
71
+ */
72
+ readonly patterns: readonly string[];
73
+ /** Check if this connection's pattern list accepts a URI. */
74
+ accepts(uri: string): boolean;
75
+ }
76
+ /**
77
+ * Wrap a client with a URI pattern list to create a connection.
78
+ *
79
+ * The connection is the gateway control — the rig uses it for
80
+ * routing within the route arrays it appears in, and the patterns
81
+ * can be published over the wire for remote filtering.
82
+ *
83
+ * Local enforcement is always applied. Remote enforcement is
84
+ * best-effort: the remote node may or may not honor the patterns,
85
+ * but the local rig always filters based on them.
86
+ */
87
+ export declare function connection(client: ProtocolInterfaceNode, patterns: string[], options?: ConnectionOptions): Connection;
88
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAQ/D,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAEvC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC,6DAA6D;IAC7D,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,qBAAqB,EAC7B,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,UAAU,CAcZ"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @module
3
+ * Connection — a client bound to a URI pattern list.
4
+ *
5
+ * A `Connection` wraps a `ProtocolInterfaceNode` with a set of URI
6
+ * filter patterns. Connections are bound into the rig's `routes`
7
+ * config (`receive`, `read`, `observe`) — each route gets its own
8
+ * ordered list of connections.
9
+ *
10
+ * The same connection value can be referenced from multiple routes
11
+ * (when one client serves writes, reads, and observes with the same
12
+ * filter); a different filter for a different op means a separate
13
+ * `connection(...)` call.
14
+ *
15
+ * Pattern syntax (same as observe and reactions):
16
+ * - `*` matches exactly one non-empty segment
17
+ * - `**` matches zero or more remaining segments (final segment only)
18
+ * - Literal segments must match exactly
19
+ *
20
+ * @example A single client serving all three ops
21
+ * ```ts
22
+ * import { connection, Rig } from "@bandeira-tech/b3nd-core";
23
+ *
24
+ * const node = connection(httpClient, ["mutable://**", "hash://**"]);
25
+ *
26
+ * const rig = new Rig({
27
+ * routes: {
28
+ * receive: [node],
29
+ * read: [node],
30
+ * observe: [node],
31
+ * },
32
+ * });
33
+ * ```
34
+ *
35
+ * @example Asymmetric topology — write-mirror, read-cache, narrow observe
36
+ * ```ts
37
+ * const primary = connection(httpClient, ["mutable://**", "hash://**"], { id: "primary" });
38
+ * const mirror = connection(pgClient, ["mutable://**", "hash://**"], { id: "mirror" });
39
+ * const cache = connection(redisClient, ["mutable://accounts/**"], { id: "cache" });
40
+ * const obsNarrow = connection(httpClient, ["mutable://**"], { id: "primary-obs" });
41
+ *
42
+ * const rig = new Rig({
43
+ * routes: {
44
+ * receive: [primary, mirror], // broadcast both
45
+ * read: [cache, primary], // try cache first, then primary
46
+ * observe: [obsNarrow], // narrow namespace, primary only
47
+ * },
48
+ * });
49
+ * ```
50
+ */
51
+ import { compilePattern, } from "../match-pattern/match-pattern.js";
52
+ // ── Internals ──
53
+ function matchesAny(matchers, uri) {
54
+ for (let i = 0; i < matchers.length; i++) {
55
+ if (matchers[i](uri))
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ // ── connection ──
61
+ /** Module-level counter for auto-generated connection IDs. */
62
+ let _autoIdCounter = 0;
63
+ /**
64
+ * Wrap a client with a URI pattern list to create a connection.
65
+ *
66
+ * The connection is the gateway control — the rig uses it for
67
+ * routing within the route arrays it appears in, and the patterns
68
+ * can be published over the wire for remote filtering.
69
+ *
70
+ * Local enforcement is always applied. Remote enforcement is
71
+ * best-effort: the remote node may or may not honor the patterns,
72
+ * but the local rig always filters based on them.
73
+ */
74
+ export function connection(client, patterns, options) {
75
+ const matchers = patterns.map(compilePattern);
76
+ const frozenPatterns = Object.freeze([...patterns]);
77
+ const id = options?.id ?? `conn-${_autoIdCounter++}`;
78
+ return {
79
+ id,
80
+ client,
81
+ patterns: frozenPatterns,
82
+ accepts(uri) {
83
+ return matchesAny(matchers, uri);
84
+ },
85
+ };
86
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @module
3
+ * Typed event emitter for the Rig.
4
+ *
5
+ * Events are async, fire-and-forget — they run AFTER the operation
6
+ * completes (after post-hooks). They never block the caller.
7
+ *
8
+ * Handler errors are caught (never propagated) and surfaced via
9
+ * `onHandlerError` listeners. If no listener is registered, they
10
+ * fall back to `console.warn` so failures are never silent.
11
+ *
12
+ * On cleanup, pending event promises are returned to the caller
13
+ * so they can choose to await them or let them go.
14
+ *
15
+ * Pure module — no Rig dependency, testable in isolation.
16
+ */
17
+ /** All possible rig event names. */
18
+ export type RigEventName = "send:success" | "send:error" | "receive:success" | "receive:error" | "read:success" | "read:error" | "*:success" | "*:error";
19
+ /** Payload delivered to event handlers. */
20
+ export interface RigEvent {
21
+ /** The operation that triggered this event. */
22
+ op: string;
23
+ /** The URI involved, if any. */
24
+ uri?: string;
25
+ /** The data involved (e.g., receive payload, send envelope). */
26
+ data?: unknown;
27
+ /** The operation result (on success). */
28
+ result?: unknown;
29
+ /** The error (on error). */
30
+ error?: unknown;
31
+ /** Timestamp when the event was emitted. */
32
+ ts: number;
33
+ }
34
+ /** Event handler function. */
35
+ export type EventHandler = (event: RigEvent) => void | Promise<void>;
36
+ /** Listener for errors thrown inside event handlers. */
37
+ export type HandlerErrorListener = (error: unknown, event: RigEventName) => void;
38
+ /**
39
+ * Typed event emitter for Rig operations.
40
+ *
41
+ * - Handlers fire asynchronously (via microtask)
42
+ * - Handler errors are routed to `onHandlerError` listeners; if none are
43
+ * registered, they fall back to `console.warn`
44
+ * - Wildcard events (`*:success`, `*:error`) fire for all operations
45
+ * - `pending()` returns in-flight handler promises for drain-on-cleanup
46
+ */
47
+ export declare class RigEventEmitter {
48
+ private handlers;
49
+ private errorListeners;
50
+ private inflight;
51
+ /** Register a handler. Returns an unsubscribe function. */
52
+ on(event: RigEventName, handler: EventHandler): () => void;
53
+ /** Remove a specific handler. */
54
+ off(event: RigEventName, handler: EventHandler): void;
55
+ /**
56
+ * Register a listener for errors thrown inside event handlers.
57
+ * Returns an unsubscribe function.
58
+ *
59
+ * When at least one listener is registered, the `console.warn` fallback
60
+ * is suppressed — the listener owns reporting. If a listener itself
61
+ * throws, that secondary error falls back to `console.warn` (no recursion).
62
+ */
63
+ onHandlerError(listener: HandlerErrorListener): () => void;
64
+ /** Return handler counts per event name. */
65
+ counts(): Record<string, number>;
66
+ /**
67
+ * Fire an event. Handlers run asynchronously and never block.
68
+ * Errors in handlers are routed to `onHandlerError` listeners (or
69
+ * `console.warn` if none). Promises are tracked so `pending()` can
70
+ * return them, and self-evict once settled.
71
+ */
72
+ emit(event: RigEventName, payload: RigEvent): void;
73
+ private dispatchHandlerError;
74
+ /**
75
+ * Return all in-flight event handler promises and clear the queue.
76
+ *
77
+ * The caller decides what to do with them:
78
+ * - `await Promise.allSettled(pending)` to drain before exit
79
+ * - Ignore them if you don't care about completion
80
+ */
81
+ pending(): Promise<void>[];
82
+ }
83
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../../../../../../src/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,oCAAoC;AACpC,MAAM,MAAM,YAAY,GACpB,cAAc,GACd,YAAY,GACZ,iBAAiB,GACjB,eAAe,GACf,cAAc,GACd,YAAY,GACZ,WAAW,GACX,SAAS,CAAC;AAEd,2CAA2C;AAC3C,MAAM,WAAW,QAAQ;IACvB,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,8BAA8B;AAC9B,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAErE,wDAAwD;AACxD,MAAM,MAAM,oBAAoB,GAAG,CACjC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,YAAY,KAChB,IAAI,CAAC;AAIV;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAA8C;IAC9D,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,QAAQ,CAA4B;IAE5C,2DAA2D;IAC3D,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAU1D,iCAAiC;IACjC,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAIrD;;;;;;;OAOG;IACH,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAK1D,4CAA4C;IAC5C,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQhC;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI;IAoBlD,OAAO,CAAC,oBAAoB;IAiB5B;;;;;;OAMG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE;CAK3B"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @module
3
+ * Typed event emitter for the Rig.
4
+ *
5
+ * Events are async, fire-and-forget — they run AFTER the operation
6
+ * completes (after post-hooks). They never block the caller.
7
+ *
8
+ * Handler errors are caught (never propagated) and surfaced via
9
+ * `onHandlerError` listeners. If no listener is registered, they
10
+ * fall back to `console.warn` so failures are never silent.
11
+ *
12
+ * On cleanup, pending event promises are returned to the caller
13
+ * so they can choose to await them or let them go.
14
+ *
15
+ * Pure module — no Rig dependency, testable in isolation.
16
+ */
17
+ // ── Emitter ──
18
+ /**
19
+ * Typed event emitter for Rig operations.
20
+ *
21
+ * - Handlers fire asynchronously (via microtask)
22
+ * - Handler errors are routed to `onHandlerError` listeners; if none are
23
+ * registered, they fall back to `console.warn`
24
+ * - Wildcard events (`*:success`, `*:error`) fire for all operations
25
+ * - `pending()` returns in-flight handler promises for drain-on-cleanup
26
+ */
27
+ export class RigEventEmitter {
28
+ handlers = new Map();
29
+ errorListeners = new Set();
30
+ inflight = new Set();
31
+ /** Register a handler. Returns an unsubscribe function. */
32
+ on(event, handler) {
33
+ let set = this.handlers.get(event);
34
+ if (!set) {
35
+ set = new Set();
36
+ this.handlers.set(event, set);
37
+ }
38
+ set.add(handler);
39
+ return () => set.delete(handler);
40
+ }
41
+ /** Remove a specific handler. */
42
+ off(event, handler) {
43
+ this.handlers.get(event)?.delete(handler);
44
+ }
45
+ /**
46
+ * Register a listener for errors thrown inside event handlers.
47
+ * Returns an unsubscribe function.
48
+ *
49
+ * When at least one listener is registered, the `console.warn` fallback
50
+ * is suppressed — the listener owns reporting. If a listener itself
51
+ * throws, that secondary error falls back to `console.warn` (no recursion).
52
+ */
53
+ onHandlerError(listener) {
54
+ this.errorListeners.add(listener);
55
+ return () => this.errorListeners.delete(listener);
56
+ }
57
+ /** Return handler counts per event name. */
58
+ counts() {
59
+ const result = {};
60
+ for (const [name, set] of this.handlers) {
61
+ if (set.size > 0)
62
+ result[name] = set.size;
63
+ }
64
+ return result;
65
+ }
66
+ /**
67
+ * Fire an event. Handlers run asynchronously and never block.
68
+ * Errors in handlers are routed to `onHandlerError` listeners (or
69
+ * `console.warn` if none). Promises are tracked so `pending()` can
70
+ * return them, and self-evict once settled.
71
+ */
72
+ emit(event, payload) {
73
+ const specific = this.handlers.get(event);
74
+ // Determine wildcard: "send:success" → "*:success"
75
+ const suffix = event.endsWith(":success") ? "*:success" : "*:error";
76
+ const wildcard = this.handlers.get(suffix);
77
+ const all = [
78
+ ...(specific ? specific : []),
79
+ ...(wildcard && event !== suffix ? wildcard : []),
80
+ ];
81
+ for (const handler of all) {
82
+ const p = Promise.resolve()
83
+ .then(() => handler(payload))
84
+ .catch((err) => this.dispatchHandlerError(err, event));
85
+ this.inflight.add(p);
86
+ p.finally(() => this.inflight.delete(p));
87
+ }
88
+ }
89
+ dispatchHandlerError(error, event) {
90
+ if (this.errorListeners.size === 0) {
91
+ console.warn(`[rig] event handler error on "${event}":`, error);
92
+ return;
93
+ }
94
+ for (const listener of this.errorListeners) {
95
+ try {
96
+ listener(error, event);
97
+ }
98
+ catch (listenerError) {
99
+ console.warn(`[rig] onHandlerError listener threw:`, listenerError);
100
+ }
101
+ }
102
+ }
103
+ /**
104
+ * Return all in-flight event handler promises and clear the queue.
105
+ *
106
+ * The caller decides what to do with them:
107
+ * - `await Promise.allSettled(pending)` to drain before exit
108
+ * - Ignore them if you don't care about completion
109
+ */
110
+ pending() {
111
+ const result = [...this.inflight];
112
+ this.inflight.clear();
113
+ return result;
114
+ }
115
+ }