@optimystic/db-p2p 0.28.0 → 0.29.0

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 (67) hide show
  1. package/dist/src/cluster/block-transfer-service.d.ts +0 -10
  2. package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
  3. package/dist/src/cluster/block-transfer-service.js +4 -2
  4. package/dist/src/cluster/block-transfer-service.js.map +1 -1
  5. package/dist/src/cluster/cluster-policy.d.ts +101 -18
  6. package/dist/src/cluster/cluster-policy.d.ts.map +1 -1
  7. package/dist/src/cluster/cluster-policy.js +153 -30
  8. package/dist/src/cluster/cluster-policy.js.map +1 -1
  9. package/dist/src/cluster/quorum-restore.d.ts +4 -2
  10. package/dist/src/cluster/quorum-restore.d.ts.map +1 -1
  11. package/dist/src/cluster/quorum-restore.js +4 -2
  12. package/dist/src/cluster/quorum-restore.js.map +1 -1
  13. package/dist/src/cluster/service.d.ts +12 -9
  14. package/dist/src/cluster/service.d.ts.map +1 -1
  15. package/dist/src/cluster/service.js +6 -6
  16. package/dist/src/cluster/service.js.map +1 -1
  17. package/dist/src/dispute/service.d.ts +1 -4
  18. package/dist/src/dispute/service.d.ts.map +1 -1
  19. package/dist/src/dispute/service.js +2 -1
  20. package/dist/src/dispute/service.js.map +1 -1
  21. package/dist/src/libp2p-key-network.d.ts +8 -2
  22. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  23. package/dist/src/libp2p-key-network.js +8 -2
  24. package/dist/src/libp2p-key-network.js.map +1 -1
  25. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  26. package/dist/src/libp2p-node-base.js +22 -19
  27. package/dist/src/libp2p-node-base.js.map +1 -1
  28. package/dist/src/logger.d.ts +28 -1
  29. package/dist/src/logger.d.ts.map +1 -1
  30. package/dist/src/logger.js +143 -1
  31. package/dist/src/logger.js.map +1 -1
  32. package/dist/src/network/network-manager-service.d.ts +1 -4
  33. package/dist/src/network/network-manager-service.d.ts.map +1 -1
  34. package/dist/src/network/network-manager-service.js +2 -1
  35. package/dist/src/network/network-manager-service.js.map +1 -1
  36. package/dist/src/repo/coordinator-repo.d.ts +183 -13
  37. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  38. package/dist/src/repo/coordinator-repo.js +686 -107
  39. package/dist/src/repo/coordinator-repo.js.map +1 -1
  40. package/dist/src/repo/service.d.ts +9 -6
  41. package/dist/src/repo/service.d.ts.map +1 -1
  42. package/dist/src/repo/service.js +4 -5
  43. package/dist/src/repo/service.js.map +1 -1
  44. package/dist/src/sync/service.d.ts +1 -2
  45. package/dist/src/sync/service.d.ts.map +1 -1
  46. package/dist/src/sync/service.js +2 -1
  47. package/dist/src/sync/service.js.map +1 -1
  48. package/dist/src/testing/mesh-harness.d.ts +7 -1
  49. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  50. package/dist/src/testing/mesh-harness.js +2 -1
  51. package/dist/src/testing/mesh-harness.js.map +1 -1
  52. package/package.json +2 -2
  53. package/readme.md +19 -0
  54. package/src/cluster/block-transfer-service.ts +4 -8
  55. package/src/cluster/cluster-policy.ts +196 -36
  56. package/src/cluster/quorum-restore.ts +4 -2
  57. package/src/cluster/service.ts +14 -9
  58. package/src/dispute/service.ts +3 -3
  59. package/src/libp2p-key-network.ts +8 -2
  60. package/src/libp2p-node-base.ts +22 -19
  61. package/src/logger.ts +196 -2
  62. package/src/network/network-manager-service.ts +414 -414
  63. package/src/protocol-client.ts +196 -196
  64. package/src/repo/coordinator-repo.ts +833 -122
  65. package/src/repo/service.ts +12 -9
  66. package/src/sync/service.ts +3 -5
  67. package/src/testing/mesh-harness.ts +8 -1
package/src/logger.ts CHANGED
@@ -1,7 +1,181 @@
1
+ import { base32 } from 'multiformats/bases/base32'
2
+ import { base58btc } from 'multiformats/bases/base58'
3
+ import { base64 } from 'multiformats/bases/base64'
1
4
  import debug from 'debug'
5
+ import type { PeerId } from '@libp2p/interface'
6
+ import type { Multiaddr } from '@multiformats/multiaddr'
7
+ import type { CID } from 'multiformats/cid'
2
8
 
3
9
  const BASE_NAMESPACE = 'optimystic:db-p2p'
4
10
 
11
+ /*
12
+ * Format specifiers, ported from `@libp2p/logger`'s `src/index.ts` (MIT, same license as this
13
+ * repo). Call sites in this package log lines like `'error handling X from %p - %e'`; those used
14
+ * to reach libp2p's own logger, which registers these. Without the port they would print the
15
+ * literal text `%p` / `%e`.
16
+ *
17
+ * NOTE: these are registered on the `debug` module instance THIS file imports. libp2p's own
18
+ * loggers use `weald` (via @libp2p/logger) and carry their own copy — the two registries are
19
+ * independent, and enabling one from test code does not enable the other.
20
+ *
21
+ * NOTE: `debug.formatters` is process-wide, and the other six packages' `createLogger` factories
22
+ * import the same `debug` module — so importing this file makes `%p`/`%e`/… work from their
23
+ * loggers too. Harmless today (no other package registers any specifier, and none of these letters
24
+ * is a `util.format` specifier except `%c`, whose Node meaning is a no-op that swallows its
25
+ * argument). If a second package ever registers one of these letters, last import wins silently;
26
+ * move the registry somewhere both can share rather than racing on it.
27
+ *
28
+ * NOTE: only `%e` is guaranteed not to throw — its call sites take a `catch`-bound `unknown`. The
29
+ * other six call `.toString()` / an encoder on whatever they are handed, so a caller that passes
30
+ * the wrong type turns a log line into an exception. That matches upstream; tighten them if a
31
+ * call site ever formats a value it did not construct.
32
+ *
33
+ * `%k` (`interface-datastore`'s `Key`) is deliberately NOT ported: `interface-datastore` is not a
34
+ * declared dependency of this package and no call site formats one. Add it if that changes.
35
+ */
36
+
37
+ // Add a formatter for converting to a base58 string
38
+ debug.formatters['b'] = (v?: Uint8Array): string => {
39
+ return v == null ? 'undefined' : base58btc.baseEncode(v)
40
+ }
41
+
42
+ // Add a formatter for converting to a base32 string
43
+ debug.formatters['t'] = (v?: Uint8Array): string => {
44
+ return v == null ? 'undefined' : base32.baseEncode(v)
45
+ }
46
+
47
+ // Add a formatter for converting to a base64 string
48
+ debug.formatters['m'] = (v?: Uint8Array): string => {
49
+ return v == null ? 'undefined' : base64.baseEncode(v)
50
+ }
51
+
52
+ // Add a formatter for stringifying peer ids
53
+ debug.formatters['p'] = (v?: PeerId): string => {
54
+ return v == null ? 'undefined' : v.toString()
55
+ }
56
+
57
+ // Add a formatter for stringifying CIDs
58
+ debug.formatters['c'] = (v?: CID): string => {
59
+ return v == null ? 'undefined' : v.toString()
60
+ }
61
+
62
+ // Add a formatter for stringifying Multiaddrs
63
+ debug.formatters['a'] = (v?: Multiaddr): string => {
64
+ return v == null ? 'undefined' : v.toString()
65
+ }
66
+
67
+ function notEmpty(str?: string): string | undefined {
68
+ if (str == null) {
69
+ return
70
+ }
71
+
72
+ str = str.trim()
73
+
74
+ if (str.length === 0) {
75
+ return
76
+ }
77
+
78
+ return str
79
+ }
80
+
81
+ function formatError(v: Error, indent = ''): string {
82
+ const message = notEmpty(v.message)
83
+ const stack = notEmpty(v.stack)
84
+
85
+ // some browser errors (mostly from Firefox) have no message or no stack,
86
+ // sometimes both, sometimes neither. Sometimes the message is in the stack,
87
+ // sometimes it isn't so try to do *something* useful
88
+ if (message != null && stack != null) {
89
+ if (stack.includes(message)) {
90
+ return `${stack.split('\n').join(`\n${indent}`)}`
91
+ }
92
+
93
+ return `${message}\n${indent}${stack.split('\n').join(`\n${indent}`)}`
94
+ }
95
+
96
+ if (stack != null) {
97
+ return `${stack.split('\n').join(`\n${indent}`)}`
98
+ }
99
+
100
+ if (message != null) {
101
+ return `${message}`
102
+ }
103
+
104
+ return `${v.toString()}`
105
+ }
106
+
107
+ function isAggregateError(err?: any): err is AggregateError {
108
+ return err instanceof AggregateError || (err?.name === 'AggregateError' && Array.isArray(err.errors))
109
+ }
110
+
111
+ function printError(err: Error, indent = ''): string {
112
+ if (isAggregateError(err)) {
113
+ let output = formatError(err, indent)
114
+
115
+ if (err.errors.length > 0) {
116
+ indent = `${indent} `
117
+
118
+ output += `\n${indent}${err.errors
119
+ .map(err => `${printError(err, `${indent}`)}`)
120
+ .join(`\n${indent}`)
121
+ }`
122
+ } else {
123
+ output += `\n${indent}[Error list was empty]`
124
+ }
125
+
126
+ return output.trim()
127
+ }
128
+
129
+ return formatError(err, indent)
130
+ }
131
+
132
+ // Add a formatter for stringifying Errors.
133
+ //
134
+ // A call site can hand `%e` anything — `catch (err)` binds `unknown`, and this package's `%e` sites
135
+ // are all in catch blocks. This must never throw: a logger that throws turns a caught error into an
136
+ // uncaught one at exactly the site that was trying to report it.
137
+ //
138
+ // The try/catch is a deliberate deviation from the upstream `@libp2p/logger` port. `formatError`'s
139
+ // last resort is `${v.toString()}`, which raises for the two values that have no usable primitive
140
+ // conversion — a null-prototype object (`throw Object.create(null)`) and a symbol. Upstream has the
141
+ // same hole; here the stated contract is "never throw", so the fallback is explicit.
142
+ debug.formatters['e'] = (v?: Error): string => {
143
+ if (v == null) {
144
+ return 'undefined'
145
+ }
146
+
147
+ try {
148
+ return printError(v)
149
+ } catch {
150
+ return '[unformattable error]'
151
+ }
152
+ }
153
+
154
+ /**
155
+ * A `debug` channel plus the severity sub-channels libp2p's own `Logger` exposes, so a call site
156
+ * can be moved between the two factories without changing what it calls.
157
+ *
158
+ * `error` and `trace` are ordinary child namespaces (`<namespace>:error`), so a wildcard filter
159
+ * the operator already uses — `optimystic:db-p2p:*` — keeps matching them. An EXACT-match filter
160
+ * (`DEBUG=optimystic:db-p2p:repo-service`) does not; that is the same caveat the peer-id suffix
161
+ * already carries, and `docs/debugging.md` already documents it.
162
+ *
163
+ * Unlike libp2p we do NOT conditionally stub out `trace`: libp2p builds a no-op unless a `:trace`
164
+ * namespace is explicitly enabled, but a disabled `debug` channel is already near-free, and the
165
+ * conditional version reads its enablement once at construction — wrong for anything built before
166
+ * `DEBUG` is set. `newScope` is deliberately omitted; `createLogger('parent:child')` says the same
167
+ * thing and nothing calls it.
168
+ *
169
+ * NOTE: because `trace` is a real channel, the wildcard `optimystic:db-p2p:*` that
170
+ * `docs/debugging.md` tells operators to set will also show trace lines. Nothing calls `.trace`
171
+ * yet, so that is currently free; if trace logging ever becomes voluminous, give the docs a
172
+ * narrower default filter rather than stubbing the channel back out.
173
+ */
174
+ export interface Logger extends debug.Debugger {
175
+ error: debug.Debugger
176
+ trace: debug.Debugger
177
+ }
178
+
5
179
  /**
6
180
  * Build a `debug` logger under `optimystic:db-p2p:<subNamespace>`, optionally suffixed with the
7
181
  * owning node's peer id (`:<first 12 chars>`) so lines from several nodes sharing one process —
@@ -17,10 +191,30 @@ const BASE_NAMESPACE = 'optimystic:db-p2p'
17
191
  * the three `peer-address-book` sinks); the package's other ~30 `createLogger` call sites
18
192
  * still log under a flat namespace. Thread a peer id through any of them if a future diagnosis
19
193
  * needs per-node attribution from that subsystem — the mechanism is already here.
194
+ *
195
+ * The peer-id suffix goes BEFORE `:error` / `:trace` — those are children of the concrete channel,
196
+ * so a two-node process gets `…:x:12D3KooWAb:error`, not `…:x:error:12D3KooWAb`.
197
+ */
198
+ /*
199
+ * NOTE: `packages/db-p2p/test/logger.spec.ts` asserts that every namespace this package emits has
200
+ * a row in the db-p2p table of `docs/debugging.md`, and it finds them by scanning `src/` for
201
+ * `createLogger("…")` / `createLogger('…')` — STRING LITERALS ONLY. A namespace built from a
202
+ * variable (`createLogger(someName)`) is invisible to that guard, so it would go undocumented
203
+ * silently. No such call site exists today; the two that pass a fallback
204
+ * (`createLogger(init.logPrefix ?? 'repo-service')`) still carry the literal, which is what the
205
+ * scan picks up. If you ever need a fully computed namespace, document it by hand and say so here.
20
206
  */
21
- export function createLogger(subNamespace: string, peerId?: string): debug.Debugger {
207
+ export function createLogger(subNamespace: string, peerId?: string): Logger {
22
208
  const suffix = peerId ? `:${peerId.substring(0, 12)}` : ''
23
- return debug(`${BASE_NAMESPACE}:${subNamespace}${suffix}`)
209
+ const namespace = `${BASE_NAMESPACE}:${subNamespace}${suffix}`
210
+ // NOTE: `Object.assign` onto the Debugger, never a spread into a fresh object. `debug` defines
211
+ // `enabled` as an accessor property on the function object it returns; assigning onto that
212
+ // object preserves the accessor, whereas spreading would flatten it to a construction-time
213
+ // snapshot boolean and silently break any `if (log.enabled)` guard.
214
+ return Object.assign(debug(namespace), {
215
+ error: debug(`${namespace}:error`),
216
+ trace: debug(`${namespace}:trace`)
217
+ })
24
218
  }
25
219
 
26
220
  export const verbose = typeof process !== 'undefined'