@msgboard/relayer 0.0.1 → 0.0.31

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 CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  A controllable, safe-by-default pool-watcher engine for the msgboard board. Runs a heartbeat: poll a **Source**, record every item to an always-on **Sink**, filter by a **Condition**, dedup via a **Store**, then gate the **Action** based on mode.
4
4
 
5
+ ## Install
6
+
7
+ ```sh
8
+ npm i @msgboard/relayer
9
+ ```
10
+
11
+ `pg` is an optional peer dependency — only required if you use `postgresStore` or `postgresArchiveSink`.
12
+
5
13
  ## Safe by default
6
14
 
7
15
  The engine has two modes:
@@ -23,10 +31,12 @@ Sink and Store are intentionally separate: the sink runs in **both** modes; the
23
31
  ## Minimal usage
24
32
 
25
33
  ```ts
34
+ import { http } from 'viem'
26
35
  import { Relayer, msgboardContentSource, noopAction } from '@msgboard/relayer'
27
36
 
28
37
  const relayer = new Relayer({
29
- node: { rpcUrl: 'https://rpc.v4.testnet.pulsechain.com', chainId: 943 },
38
+ node: { transport: http('https://rpc.pulsechain.com') },
39
+ // chain auto-detected via eth_chainId; pass node.chain to override
30
40
  // mode defaults to 'observe' — no on-chain writes
31
41
  source: msgboardContentSource({ category: 'myapp' }),
32
42
  key: (msg) => msg.hash,
@@ -51,6 +61,54 @@ const recent = await archive.query({ chainId: 943, category: 'lorem', limit: 20
51
61
 
52
62
  `query()` filters by `chainId`, `category` (hex or decoded text), `since`/`until`, `contains` (substring match on decoded content), `limit`, and `offset`.
53
63
 
64
+ The storage and query layer lives in [`@msgboard/history`](../history); `postgresArchiveSink` is the adapter that drives it from the relayer heartbeat. Use `@msgboard/history`'s `archiveServer` to expose the same archive over an HTTP query API.
65
+
66
+ ## "Write for me" relay
67
+
68
+ A push-based relay pattern where clients solve proof-of-work locally and POST the result — the relay forwards it on-chain on their behalf.
69
+
70
+ ```ts
71
+ import { http, isHex, type Hex } from 'viem'
72
+ import { Relayer, httpQueueSource, forwardMessageAction, defaultLogger } from '@msgboard/relayer'
73
+
74
+ const queue = httpQueueSource<Hex>({
75
+ port: 3001,
76
+ token: process.env.RELAY_TOKEN,
77
+ parse: (body) => {
78
+ const { rlp } = body as { rlp: string }
79
+ if (!isHex(rlp)) throw new Error('expected hex rlp')
80
+ return rlp as Hex
81
+ },
82
+ })
83
+
84
+ const relayer = new Relayer<Hex>({
85
+ node: { transport: http('https://rpc.pulsechain.com') },
86
+ mode: 'live',
87
+ source: queue,
88
+ key: (rlp) => rlp,
89
+ action: forwardMessageAction(),
90
+ logger: defaultLogger('relay'),
91
+ })
92
+
93
+ relayer.start()
94
+ ```
95
+
96
+ Clients submit with:
97
+
98
+ ```sh
99
+ curl -X POST http://localhost:3001/submit \
100
+ -H 'Content-Type: application/json' \
101
+ -d '{"rlp":"0x..."}'
102
+ ```
103
+
104
+ The `rlp` value comes from the SDK client's `doPoW()` result: `work.message`. The relay calls `msgboard_addMessage` with it directly — no wallet, no second proof-of-work.
105
+
106
+ `httpQueueSource` buffers POSTed items in memory and drains them on each heartbeat tick. An optional `token` field enables bearer-token auth. See `examples/write-for-me.ts` for a full runnable version.
107
+
108
+ ### Transform anything
109
+
110
+ Because `httpQueueSource` is generic and `forwardMessageAction` only needs a `Hex` RLP, you can build relays for arbitrary protocols by adding a transform step: accept whatever your protocol produces, convert it to a `msgboard_addMessage`-compatible RLP in `parse`, and let the relayer forward it.
111
+
54
112
  ## Example relayers
55
113
 
56
114
  | Relayer | source | store | sink | action (live only) | demonstrates |
@@ -59,10 +117,11 @@ const recent = await archive.query({ chainId: 943, category: 'lorem', limit: 20
59
117
  | Bridge watcher (`bridge.ts`) | `bridgeAffirmationSource` (per chain) | memory-ttl | — | `submitMessageAction` | finalized event source, multi-node |
60
118
  | Spam writer (`spam.ts`) | `generatedSource(sentence)` | noop | — | `submitMessageAction` | producer source, noop dedup |
61
119
  | Archivist | all content | — | `postgresArchiveSink` 1yr | `noopAction` | sink-only; records in observe mode |
120
+ | "Write for me" relay (`write-for-me.ts`) | `httpQueueSource` (POSTed RLP) | noop | — | `forwardMessageAction` | push-based, client-side PoW |
62
121
  | Cross-chain mirror | content on 369 | memory-ttl | — | `submitMessageAction` on 943 | source node ≠ action node |
63
122
  | Moderation flagger | all content + blocklist predicate | — | `postgresSink('flagged')` | `noopAction` | condition + sink, no action |
64
123
 
65
- See `examples/` for runnable code for the archivist, mirror, and flagger.
124
+ See `examples/` for runnable code for the archivist, mirror, flagger, and write-for-me relay.
66
125
 
67
126
  ## Known limitations
68
127
 
@@ -0,0 +1,13 @@
1
+ import type { Hex } from 'viem';
2
+ import type { RelayerAction } from '../types.js';
3
+ /**
4
+ * Forwards a pre-computed RLP-encoded message to the board without doing
5
+ * proof-of-work. The item must already be a valid RLP hex string produced by
6
+ * the client's `doPoW` → `message` field.
7
+ *
8
+ * Use this with `httpQueueSource` to build a "write for you" relay: clients
9
+ * solve their own proof-of-work locally then POST the result; the relay
10
+ * submits it on-chain.
11
+ */
12
+ export declare const forwardMessageAction: () => RelayerAction<Hex>;
13
+ //# sourceMappingURL=forward-message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward-message.d.ts","sourceRoot":"","sources":["../../src/actions/forward-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,QAAO,aAAa,CAAC,GAAG,CAMvD,CAAA"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Forwards a pre-computed RLP-encoded message to the board without doing
3
+ * proof-of-work. The item must already be a valid RLP hex string produced by
4
+ * the client's `doPoW` → `message` field.
5
+ *
6
+ * Use this with `httpQueueSource` to build a "write for you" relay: clients
7
+ * solve their own proof-of-work locally then POST the result; the relay
8
+ * submits it on-chain.
9
+ */
10
+ export const forwardMessageAction = () => ({
11
+ describe: (item) => `forward pre-computed message ${item.slice(0, 10)}…`,
12
+ execute: async (item, context) => {
13
+ const hash = await context.client.addMessage(item);
14
+ return { ok: true, ref: hash };
15
+ },
16
+ });
17
+ //# sourceMappingURL=forward-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward-message.js","sourceRoot":"","sources":["../../src/actions/forward-message.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAuB,EAAE,CAAC,CAAC;IAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,gCAAgC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG;IACxE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QAC/B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QAClD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;IAChC,CAAC;CACF,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"send-value.d.ts","sourceRoot":"","sources":["../../src/actions/send-value.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,YAAY,EAIlB,MAAM,MAAM,CAAA;AACb,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEhE,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI;IACtC,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,iDAAiD;IACjD,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAA;IACxD,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,6DAA6D;IAC7D,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,YAAY,CAAA;CAC1D,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,SAAS,sBAAsB,CAAC,CAAC,CAAC,KAAG,aAAa,CAAC,CAAC,CAyBtF,CAAA"}
1
+ {"version":3,"file":"send-value.d.ts","sourceRoot":"","sources":["../../src/actions/send-value.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,YAAY,EAGlB,MAAM,MAAM,CAAA;AACb,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEhE,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI;IACtC,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,iDAAiD;IACjD,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAA;IACxD,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,6DAA6D;IAC7D,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,YAAY,CAAA;CAC1D,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,SAAS,sBAAsB,CAAC,CAAC,CAAC,KAAG,aAAa,CAAC,CAAC,CAyBtF,CAAA"}
@@ -1,11 +1,11 @@
1
- import { createWalletClient, formatEther, http, } from 'viem';
1
+ import { createWalletClient, formatEther, } from 'viem';
2
2
  /** Sends native coin to an address derived from each item; waits for the receipt. */
3
3
  export const sendValueAction = (options) => {
4
4
  const makeWallet = (context) => options.walletFactory?.(context) ??
5
5
  createWalletClient({
6
6
  account: options.account,
7
7
  chain: context.chain,
8
- transport: http(context.node.rpcUrl, { timeout: 30_000 }),
8
+ transport: context.node.transport,
9
9
  });
10
10
  return {
11
11
  describe: (item, context) => `send ${formatEther(options.amount)} to ${options.recipient(item, context)}`,
@@ -1 +1 @@
1
- {"version":3,"file":"send-value.js","sourceRoot":"","sources":["../../src/actions/send-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,kBAAkB,EAClB,WAAW,EACX,IAAI,GACL,MAAM,MAAM,CAAA;AAgBb,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAI,OAAkC,EAAoB,EAAE;IACzF,MAAM,UAAU,GAAG,CAAC,OAAuB,EAAgB,EAAE,CAC3D,OAAO,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC;QAChC,kBAAkB,CAAC;YACjB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;SAC1D,CAAC,CAAA;IACJ,OAAO;QACL,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAC1B,QAAQ,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;QAC9E,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;YAClC,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC;gBACxC,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,EAAE;gBACF,KAAK,EAAE,OAAO,CAAC,MAAM;gBACrB,GAAG,EAAE,OAAO,CAAC,GAAG;aACjB,CAAC,CAAA;YACF,MAAM,OAAO,CAAC,YAAY,CAAC,yBAAyB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;YAC9D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;QAChC,CAAC;KACF,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"send-value.js","sourceRoot":"","sources":["../../src/actions/send-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,kBAAkB,EAClB,WAAW,GACZ,MAAM,MAAM,CAAA;AAgBb,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAI,OAAkC,EAAoB,EAAE;IACzF,MAAM,UAAU,GAAG,CAAC,OAAuB,EAAgB,EAAE,CAC3D,OAAO,CAAC,aAAa,EAAE,CAAC,OAAO,CAAC;QAChC,kBAAkB,CAAC;YACjB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS;SAClC,CAAC,CAAA;IACJ,OAAO;QACL,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAC1B,QAAQ,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;QAC9E,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;YAClC,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC3C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC;gBACxC,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,EAAE;gBACF,KAAK,EAAE,OAAO,CAAC,MAAM;gBACrB,GAAG,EAAE,OAAO,CAAC,GAAG;aACjB,CAAC,CAAA;YACF,MAAM,OAAO,CAAC,YAAY,CAAC,yBAAyB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;YAC9D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;QAChC,CAAC;KACF,CAAA;AACH,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -14,7 +14,10 @@ export { msgboardContentSource } from './sources/msgboard-content.js';
14
14
  export { bridgeAffirmationSource } from './sources/bridge-affirmation.js';
15
15
  export { generatedSource } from './sources/generated.js';
16
16
  export { submitMessageAction } from './actions/submit-message.js';
17
+ export { forwardMessageAction } from './actions/forward-message.js';
17
18
  export { sendValueAction } from './actions/send-value.js';
18
19
  export { webhookAction } from './actions/webhook.js';
19
20
  export { noopAction } from './actions/noop.js';
21
+ export { httpQueueSource } from './sources/http-queue.js';
22
+ export type { HttpQueueSource, HttpQueueSourceOptions } from './sources/http-queue.js';
20
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAErD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAClG,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAErD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAClG,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA"}
package/dist/index.js CHANGED
@@ -10,7 +10,9 @@ export { msgboardContentSource } from './sources/msgboard-content.js';
10
10
  export { bridgeAffirmationSource } from './sources/bridge-affirmation.js';
11
11
  export { generatedSource } from './sources/generated.js';
12
12
  export { submitMessageAction } from './actions/submit-message.js';
13
+ export { forwardMessageAction } from './actions/forward-message.js';
13
14
  export { sendValueAction } from './actions/send-value.js';
14
15
  export { webhookAction } from './actions/webhook.js';
15
16
  export { noopAction } from './actions/noop.js';
17
+ export { httpQueueSource } from './sources/http-queue.js';
16
18
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAgB1C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAgB1C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA"}
package/dist/relayer.d.ts CHANGED
@@ -6,7 +6,7 @@ import type { RelayerConfig, RelayerMode, TickReport } from './types.js';
6
6
  export declare class Relayer<T> {
7
7
  private readonly config;
8
8
  private readonly logger;
9
- private readonly context;
9
+ private contextPromise;
10
10
  private readonly intervalMs;
11
11
  private readonly pruneEveryTicks;
12
12
  private tickCount;
@@ -15,6 +15,7 @@ export declare class Relayer<T> {
15
15
  private abort;
16
16
  constructor(config: RelayerConfig<T>);
17
17
  get mode(): RelayerMode;
18
+ private ensureContext;
18
19
  /** Runs a single tick and returns a report. Used by tests and one-shot runs. */
19
20
  runOnce(): Promise<TickReport>;
20
21
  /** Begins the poll loop. Idempotent — a second call is a no-op while running. */
@@ -1 +1 @@
1
- {"version":3,"file":"relayer.d.ts","sourceRoot":"","sources":["../src/relayer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAkB,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAuCxF;;;GAGG;AACH,qBAAa,OAAO,CAAC,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,KAAK,CAA+B;gBAEhC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAQpC,IAAI,IAAI,IAAI,WAAW,CAEtB;IAED,gFAAgF;IAC1E,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAmBpC,iFAAiF;IACjF,KAAK,IAAI,IAAI;IAQb,oDAAoD;IAC9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YASb,IAAI;YAYJ,UAAU;YAWV,UAAU;YAMV,UAAU;YAcV,SAAS;YAiBT,UAAU;CAKzB"}
1
+ {"version":3,"file":"relayer.d.ts","sourceRoot":"","sources":["../src/relayer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAkB,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAoDxF;;;GAGG;AACH,qBAAa,OAAO,CAAC,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,KAAK,CAA+B;gBAEhC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAOpC,IAAI,IAAI,IAAI,WAAW,CAEtB;IAED,OAAO,CAAC,aAAa;IAOrB,gFAAgF;IAC1E,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAoBpC,iFAAiF;IACjF,KAAK,IAAI,IAAI;IAQb,oDAAoD;IAC9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YASb,IAAI;YAYJ,UAAU;YAWV,UAAU;YAMV,UAAU;YAeV,SAAS;YAiBT,UAAU;CAKzB"}
package/dist/relayer.js CHANGED
@@ -1,19 +1,30 @@
1
- import { createPublicClient, http } from 'viem';
1
+ import { createPublicClient } from 'viem';
2
2
  import { MsgBoardClient } from '@msgboard/sdk';
3
3
  import { resolveChain } from './chains.js';
4
4
  import { defaultLogger } from './logger.js';
5
5
  const DEFAULT_INTERVAL_MS = 30_000;
6
6
  const DEFAULT_PRUNE_EVERY_TICKS = 30;
7
+ /** Calls eth_chainId on the node and returns the numeric chain id. */
8
+ const detectChainId = async (transport) => {
9
+ const probe = createPublicClient({ transport });
10
+ return probe.getChainId();
11
+ };
7
12
  /** Builds the runtime context (viem + SDK clients) for a relayer config. */
8
- const buildContext = (config, logger) => {
9
- const chain = resolveChain(config.node.chainId);
10
- const publicClient = createPublicClient({
11
- chain,
12
- transport: http(config.node.rpcUrl, { timeout: 30_000 }),
13
- });
13
+ const buildContext = async (config, logger) => {
14
+ const node = config.node;
15
+ const chain = node.chain ?? await (async () => {
16
+ const id = await detectChainId(node.transport);
17
+ try {
18
+ return resolveChain(id);
19
+ }
20
+ catch {
21
+ throw new Error(`detected chain ${id} from the node is not a known network — pass node.chain explicitly to support it`);
22
+ }
23
+ })();
24
+ const publicClient = createPublicClient({ chain, transport: node.transport });
14
25
  const client = new MsgBoardClient(publicClient);
15
26
  return {
16
- node: config.node,
27
+ node,
17
28
  mode: config.mode ?? 'observe',
18
29
  chain,
19
30
  publicClient,
@@ -44,7 +55,7 @@ const sleep = (ms, signal) => {
44
55
  export class Relayer {
45
56
  config;
46
57
  logger;
47
- context;
58
+ contextPromise = null;
48
59
  intervalMs;
49
60
  pruneEveryTicks;
50
61
  tickCount = 0;
@@ -54,15 +65,21 @@ export class Relayer {
54
65
  constructor(config) {
55
66
  this.config = config;
56
67
  this.logger = config.logger ?? defaultLogger('relayer');
57
- this.context = buildContext(config, this.logger);
58
68
  this.intervalMs = config.intervalMs ?? DEFAULT_INTERVAL_MS;
59
69
  this.pruneEveryTicks = config.pruneEveryTicks ?? DEFAULT_PRUNE_EVERY_TICKS;
60
70
  }
61
71
  get mode() {
62
- return this.context.mode;
72
+ return this.config.mode ?? 'observe';
73
+ }
74
+ ensureContext() {
75
+ if (!this.contextPromise) {
76
+ this.contextPromise = buildContext(this.config, this.logger);
77
+ }
78
+ return this.contextPromise;
63
79
  }
64
80
  /** Runs a single tick and returns a report. Used by tests and one-shot runs. */
65
81
  async runOnce() {
82
+ const ctx = await this.ensureContext();
66
83
  const report = {
67
84
  polled: 0,
68
85
  recorded: 0,
@@ -71,10 +88,10 @@ export class Relayer {
71
88
  described: 0,
72
89
  deduped: 0,
73
90
  };
74
- const items = await this.config.source.poll(this.context);
91
+ const items = await this.config.source.poll(ctx);
75
92
  report.polled = items.length;
76
93
  for (const item of items) {
77
- await this.handleItem(item, report);
94
+ await this.handleItem(item, report, ctx);
78
95
  }
79
96
  this.tickCount += 1;
80
97
  await this.maybePrune();
@@ -112,26 +129,26 @@ export class Relayer {
112
129
  await sleep(this.intervalMs, signal);
113
130
  }
114
131
  }
115
- async handleItem(item, report) {
116
- await this.recordItem(item, report);
117
- const eligible = await this.isEligible(item);
132
+ async handleItem(item, report, ctx) {
133
+ await this.recordItem(item, report, ctx);
134
+ const eligible = await this.isEligible(item, ctx);
118
135
  if (!eligible.proceed) {
119
136
  if (eligible.reason === 'deduped')
120
137
  report.deduped += 1;
121
138
  return;
122
139
  }
123
140
  report.eligible += 1;
124
- await this.actOnItem(item, report);
141
+ await this.actOnItem(item, report, ctx);
125
142
  }
126
- async recordItem(item, report) {
143
+ async recordItem(item, report, ctx) {
127
144
  if (!this.config.sink)
128
145
  return;
129
- await this.config.sink.record(item, this.context);
146
+ await this.config.sink.record(item, ctx);
130
147
  report.recorded += 1;
131
148
  }
132
- async isEligible(item) {
149
+ async isEligible(item, ctx) {
133
150
  if (this.config.condition) {
134
- const ok = await this.config.condition(item, this.context);
151
+ const ok = await this.config.condition(item, ctx);
135
152
  if (!ok)
136
153
  return { proceed: false, reason: 'condition' };
137
154
  }
@@ -142,14 +159,14 @@ export class Relayer {
142
159
  }
143
160
  return { proceed: true };
144
161
  }
145
- async actOnItem(item, report) {
146
- if (this.context.mode === 'observe') {
147
- this.logger('observe: %s', this.config.action.describe(item, this.context));
162
+ async actOnItem(item, report, ctx) {
163
+ if (ctx.mode === 'observe') {
164
+ this.logger('observe: %s', this.config.action.describe(item, ctx));
148
165
  report.described += 1;
149
166
  return;
150
167
  }
151
168
  try {
152
- const result = await this.config.action.execute(item, this.context);
169
+ const result = await this.config.action.execute(item, ctx);
153
170
  report.executed += 1;
154
171
  if (this.config.store) {
155
172
  await this.config.store.remember(this.config.key(item), result);
@@ -1 +1 @@
1
- {"version":3,"file":"relayer.js","sourceRoot":"","sources":["../src/relayer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relayer.js","sourceRoot":"","sources":["../src/relayer.ts"],"names":[],"mappings":"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"}
@@ -1,42 +1,19 @@
1
+ import type { ArchiveQuery, ArchiveRetention, ArchivedMessage } from '@msgboard/history';
1
2
  import type { RPCMessage } from '@msgboard/sdk';
2
3
  import type { RelayerSink } from '../types.js';
3
4
  import type { Queryable } from '../stores/postgres.js';
4
- export type ArchiveRetention = {
5
- /** Rows older than this many days are pruned. */
6
- days: number;
7
- };
5
+ export type { ArchiveQuery, ArchiveRetention, ArchivedMessage };
8
6
  export type PostgresArchiveOptions = {
9
7
  pool: Queryable;
10
8
  retention: ArchiveRetention;
11
9
  };
12
- /** Filters for querying the historical archive. */
13
- export type ArchiveQuery = {
14
- chainId?: number;
15
- /** A bytes32 hex category or its decoded text. */
16
- category?: string;
17
- since?: Date;
18
- until?: Date;
19
- /** Substring match on decoded content. */
20
- contains?: string;
21
- limit?: number;
22
- offset?: number;
23
- };
24
- /** A row of the historical archive. */
25
- export type ArchivedMessage = {
26
- hash: string;
27
- chain_id: number;
28
- category: string | null;
29
- category_text: string | null;
30
- data: string | null;
31
- content: string | null;
32
- block_number: string | null;
33
- block_hash: string | null;
34
- first_seen_at: string;
35
- };
36
10
  /**
37
- * The historical index of every message seen flowing through the board. An
38
- * ever-growing table, pruned to a retention window (default one year). `record`
39
- * is idempotent on `(hash, chain_id)`. Call `migrate()` once at startup.
11
+ * The historical index of every message seen flowing through the board, backed by
12
+ * `@msgboard/history`. Adapts that archive to the relayer's sink interface: `record`
13
+ * is driven by the relayer heartbeat (chain id taken from the tick context), while
14
+ * `migrate`/`prune`/`query` pass straight through. An ever-growing table pruned to a
15
+ * retention window (default one year); `record` is idempotent on `(hash, chain_id)`.
16
+ * Call `migrate()` once at startup.
40
17
  */
41
18
  export declare const postgresArchiveSink: (options: PostgresArchiveOptions) => RelayerSink<RPCMessage> & {
42
19
  migrate(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-archive.d.ts","sourceRoot":"","sources":["../../src/sinks/postgres-archive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,SAAS,CAAA;IACf,SAAS,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAED,mDAAmD;AACnD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,uCAAuC;AACvC,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAeD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,sBAAsB,KAC9B,WAAW,CAAC,UAAU,CAAC,GAAG;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;CA+ExD,CAAA"}
1
+ {"version":3,"file":"postgres-archive.d.ts","sourceRoot":"","sources":["../../src/sinks/postgres-archive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAItD,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAA;AAE/D,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,SAAS,CAAA;IACf,SAAS,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,sBAAsB,KAC9B,WAAW,CAAC,UAAU,CAAC,GAAG;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,KAAK,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;CASxD,CAAA"}
@@ -1,85 +1,19 @@
1
- import { hexToString } from 'viem';
2
- /** Decodes a hex blob to text, stripping null padding and returning null if not printable. */
3
- const tryDecodeText = (hex) => {
4
- try {
5
- const text = hexToString(hex).replace(/\0+$/g, '').trim();
6
- if (text.length === 0)
7
- return null;
8
- // Reject blobs with non-printable control characters
9
- if (/[\x00-\x1f\x7f]/u.test(text))
10
- return null;
11
- return text;
12
- }
13
- catch {
14
- return null;
15
- }
16
- };
1
+ import { createArchive } from '@msgboard/history';
17
2
  /**
18
- * The historical index of every message seen flowing through the board. An
19
- * ever-growing table, pruned to a retention window (default one year). `record`
20
- * is idempotent on `(hash, chain_id)`. Call `migrate()` once at startup.
3
+ * The historical index of every message seen flowing through the board, backed by
4
+ * `@msgboard/history`. Adapts that archive to the relayer's sink interface: `record`
5
+ * is driven by the relayer heartbeat (chain id taken from the tick context), while
6
+ * `migrate`/`prune`/`query` pass straight through. An ever-growing table pruned to a
7
+ * retention window (default one year); `record` is idempotent on `(hash, chain_id)`.
8
+ * Call `migrate()` once at startup.
21
9
  */
22
10
  export const postgresArchiveSink = (options) => {
23
- const { pool } = options;
24
- const retentionDays = options.retention.days;
25
- const migrate = async () => {
26
- await pool.query(`CREATE TABLE IF NOT EXISTS message_archive (
27
- hash TEXT NOT NULL,
28
- chain_id INTEGER NOT NULL,
29
- category TEXT,
30
- category_text TEXT,
31
- data TEXT,
32
- content TEXT,
33
- block_number BIGINT,
34
- block_hash TEXT,
35
- first_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(),
36
- PRIMARY KEY (hash, chain_id)
37
- )`);
38
- await pool.query(`CREATE INDEX IF NOT EXISTS message_archive_seen_idx ON message_archive (first_seen_at)`);
39
- await pool.query(`CREATE INDEX IF NOT EXISTS message_archive_chain_seen ON message_archive (chain_id, first_seen_at)`);
40
- await pool.query(`CREATE INDEX IF NOT EXISTS message_archive_category_idx ON message_archive (category)`);
41
- };
42
- const record = async (message, context) => {
43
- await pool.query(`INSERT INTO message_archive
44
- (hash, chain_id, category, category_text, data, content, block_number, block_hash)
45
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
46
- ON CONFLICT (hash, chain_id) DO NOTHING`, [
47
- message.hash,
48
- context.node.chainId,
49
- message.category,
50
- tryDecodeText(message.category),
51
- message.data,
52
- tryDecodeText(message.data),
53
- BigInt(message.blockNumber).toString(),
54
- message.blockHash,
55
- ]);
56
- };
57
- const prune = async () => {
58
- await pool.query(`DELETE FROM message_archive WHERE first_seen_at < now() - INTERVAL '${retentionDays} days'`);
59
- };
60
- const query = async (filter) => {
61
- const clauses = [];
62
- const params = [];
63
- const add = (clause, value) => {
64
- params.push(value);
65
- clauses.push(clause.replace(/\$\?/g, `$${params.length}`));
66
- };
67
- if (filter.chainId !== undefined)
68
- add('chain_id = $?', filter.chainId);
69
- if (filter.category !== undefined)
70
- add('(category = $? OR category_text = $?)', filter.category);
71
- if (filter.since)
72
- add('first_seen_at >= $?', filter.since.toISOString());
73
- if (filter.until)
74
- add('first_seen_at <= $?', filter.until.toISOString());
75
- if (filter.contains)
76
- add('content ILIKE $?', `%${filter.contains}%`);
77
- const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
78
- const limit = Math.min(Math.max(Number.parseInt(String(filter.limit ?? 100), 10) || 100, 1), 1000);
79
- const offset = Math.max(Number.parseInt(String(filter.offset ?? 0), 10) || 0, 0);
80
- const { rows } = await pool.query(`SELECT hash, chain_id, category, category_text, data, content, block_number, block_hash, first_seen_at FROM message_archive ${where} ORDER BY first_seen_at DESC LIMIT ${limit} OFFSET ${offset}`, params);
81
- return rows;
11
+ const archive = createArchive({ pool: options.pool, retention: options.retention });
12
+ return {
13
+ migrate: archive.migrate,
14
+ prune: archive.prune,
15
+ query: archive.query,
16
+ record: (message, context) => archive.record(message, context.chain.id),
82
17
  };
83
- return { record, prune, migrate, query };
84
18
  };
85
19
  //# sourceMappingURL=postgres-archive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-archive.js","sourceRoot":"","sources":["../../src/sinks/postgres-archive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"postgres-archive.js","sourceRoot":"","sources":["../../src/sinks/postgres-archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAejD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAA+B,EAI/B,EAAE;IACF,MAAM,OAAO,GAAG,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;IACnF,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,CAAC,OAAmB,EAAE,OAAuB,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;KACpG,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,55 @@
1
+ import type { RelayerSource } from '../types.js';
2
+ export type HttpQueueSourceOptions<T> = {
3
+ /** Port to listen on. Defaults to 3001. */
4
+ port?: number;
5
+ /**
6
+ * Host / interface to bind. Defaults to `'127.0.0.1'` (loopback only).
7
+ * Set to `'0.0.0.0'` for LAN/Internet exposure — requires `token` to be
8
+ * set, or the server refuses to start.
9
+ */
10
+ host?: string;
11
+ /**
12
+ * Parses the raw JSON body into a typed item. Throw to reject.
13
+ * The returned item is added to the next poll batch.
14
+ */
15
+ parse: (body: unknown) => T;
16
+ /**
17
+ * Optional bearer token — requests without `Authorization: Bearer <token>`
18
+ * receive a 401 and are not queued.
19
+ */
20
+ token?: string;
21
+ /**
22
+ * Maximum number of items held in memory before new submissions are
23
+ * rejected with 429. Defaults to 1000. Set to 0 to disable the cap.
24
+ */
25
+ maxQueueSize?: number;
26
+ /**
27
+ * Maximum number of items drained per poll tick. Defaults to 100.
28
+ * Prevents a single heartbeat from firing an unbounded burst of on-chain
29
+ * transactions if the queue fills up.
30
+ */
31
+ maxBatchSize?: number;
32
+ };
33
+ export type HttpQueueSource<T> = RelayerSource<T> & {
34
+ /** Closes the HTTP server. Call after `relayer.stop()` to free the port. */
35
+ close(): Promise<void>;
36
+ };
37
+ /**
38
+ * Opens an HTTP server that accepts `POST /submit` requests. Each accepted
39
+ * item is held in memory until the next `poll()` cycle drains the queue.
40
+ *
41
+ * Clients POST JSON matching whatever shape `parse` expects. On success they
42
+ * receive `{ ok: true, queued: true }` immediately — they don't wait for the
43
+ * relayer to process the item.
44
+ *
45
+ * Security defaults:
46
+ * - Binds to `127.0.0.1` (loopback only) unless `host` is set.
47
+ * - Non-loopback binds require `token` to be set; the server throws otherwise.
48
+ * - Queue is capped at 1000 items (429 when full).
49
+ * - Each poll drains at most 100 items.
50
+ * - Request bodies are rejected above 64 KiB.
51
+ * - `server.headersTimeout` and `server.requestTimeout` are set to 10 s
52
+ * to bound slow-loris connections.
53
+ */
54
+ export declare const httpQueueSource: <T>(options: HttpQueueSourceOptions<T>) => HttpQueueSource<T>;
55
+ //# sourceMappingURL=http-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-queue.d.ts","sourceRoot":"","sources":["../../src/sources/http-queue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKhD,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI;IACtC,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,CAAA;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG;IAClD,4EAA4E;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AA+BD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,SAAS,sBAAsB,CAAC,CAAC,CAAC,KAAG,eAAe,CAAC,CAAC,CAmDxF,CAAA"}
@@ -0,0 +1,97 @@
1
+ import { createServer } from 'node:http';
2
+ /** 64 KiB — generous ceiling for any single RLP payload. */
3
+ const MAX_BODY_BYTES = 65_536;
4
+ const readBody = (req) => new Promise((resolve, reject) => {
5
+ const contentLength = Number(req.headers['content-length'] ?? 0);
6
+ if (contentLength > MAX_BODY_BYTES) {
7
+ req.resume();
8
+ return reject(new Error('request body too large'));
9
+ }
10
+ let size = 0;
11
+ const chunks = [];
12
+ req.on('data', (chunk) => {
13
+ size += chunk.length;
14
+ if (size > MAX_BODY_BYTES) {
15
+ req.destroy();
16
+ return reject(new Error('request body too large'));
17
+ }
18
+ chunks.push(chunk);
19
+ });
20
+ req.on('end', () => {
21
+ try {
22
+ resolve(JSON.parse(Buffer.concat(chunks).toString()));
23
+ }
24
+ catch {
25
+ reject(new Error('invalid JSON'));
26
+ }
27
+ });
28
+ req.on('error', reject);
29
+ });
30
+ const respond = (res, status, body) => {
31
+ const json = JSON.stringify(body);
32
+ res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(json) });
33
+ res.end(json);
34
+ };
35
+ /**
36
+ * Opens an HTTP server that accepts `POST /submit` requests. Each accepted
37
+ * item is held in memory until the next `poll()` cycle drains the queue.
38
+ *
39
+ * Clients POST JSON matching whatever shape `parse` expects. On success they
40
+ * receive `{ ok: true, queued: true }` immediately — they don't wait for the
41
+ * relayer to process the item.
42
+ *
43
+ * Security defaults:
44
+ * - Binds to `127.0.0.1` (loopback only) unless `host` is set.
45
+ * - Non-loopback binds require `token` to be set; the server throws otherwise.
46
+ * - Queue is capped at 1000 items (429 when full).
47
+ * - Each poll drains at most 100 items.
48
+ * - Request bodies are rejected above 64 KiB.
49
+ * - `server.headersTimeout` and `server.requestTimeout` are set to 10 s
50
+ * to bound slow-loris connections.
51
+ */
52
+ export const httpQueueSource = (options) => {
53
+ const host = options.host ?? '127.0.0.1';
54
+ const maxQueueSize = options.maxQueueSize ?? 1000;
55
+ const maxBatchSize = options.maxBatchSize ?? 100;
56
+ const isNonLoopback = host !== '127.0.0.1' && host !== 'localhost' && host !== '::1';
57
+ if (isNonLoopback && !options.token) {
58
+ throw new Error(`httpQueueSource: non-loopback bind (${host}) requires a token to be set — ` +
59
+ `pass token or set host to '127.0.0.1'`);
60
+ }
61
+ const queue = [];
62
+ const server = createServer(async (req, res) => {
63
+ if (req.method !== 'POST' || req.url !== '/submit') {
64
+ return respond(res, 404, { ok: false, error: 'not found' });
65
+ }
66
+ if (options.token) {
67
+ const auth = req.headers['authorization'];
68
+ if (auth !== `Bearer ${options.token}`) {
69
+ return respond(res, 401, { ok: false, error: 'unauthorized' });
70
+ }
71
+ }
72
+ if (maxQueueSize > 0 && queue.length >= maxQueueSize) {
73
+ return respond(res, 429, { ok: false, error: 'queue full — try again later' });
74
+ }
75
+ try {
76
+ const body = await readBody(req);
77
+ const item = options.parse(body);
78
+ queue.push(item);
79
+ respond(res, 200, { ok: true, queued: true });
80
+ }
81
+ catch (err) {
82
+ respond(res, 400, { ok: false, error: err instanceof Error ? err.message : 'bad request' });
83
+ }
84
+ });
85
+ // Bound slow-loris connections.
86
+ server.headersTimeout = 10_000;
87
+ server.requestTimeout = 10_000;
88
+ server.listen(options.port ?? 3001, host);
89
+ return {
90
+ poll: async () => {
91
+ const batch = queue.splice(0, maxBatchSize);
92
+ return batch;
93
+ },
94
+ close: () => new Promise((resolve, reject) => server.close((err) => err ? reject(err) : resolve())),
95
+ };
96
+ };
97
+ //# sourceMappingURL=http-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-queue.js","sourceRoot":"","sources":["../../src/sources/http-queue.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,21 +1,24 @@
1
1
  import type { MsgBoardClient } from '@msgboard/sdk';
2
- import type { Chain, PublicClient } from 'viem';
2
+ import type { Chain, PublicClient, Transport } from 'viem';
3
3
  import type { Logger } from './logger.js';
4
4
  /** The two operating modes. `observe` never produces an outbound side effect. */
5
5
  export type RelayerMode = 'observe' | 'live';
6
6
  /** Identifies the msgboard node a relayer watches. */
7
7
  export type RelayerNode = {
8
- /** The JSON-RPC URL of the msgboard node. */
9
- rpcUrl: string;
10
- /** The chain id of the node (1, 369, or 943). */
11
- chainId: number;
8
+ /** viem Transport for the node (e.g. `http('https://...')`). */
9
+ transport: Transport;
10
+ /**
11
+ * viem Chain definition. When omitted, the chain id is detected automatically
12
+ * via `eth_chainId` on the first tick. Pass explicitly for custom networks.
13
+ */
14
+ chain?: Chain;
12
15
  };
13
16
  /** Everything a source, action, or sink may need at runtime. */
14
17
  export type RelayerContext = {
15
18
  node: RelayerNode;
16
19
  mode: RelayerMode;
17
20
  chain: Chain;
18
- /** A viem public client over `node.rpcUrl`. */
21
+ /** A viem public client backed by `node.transport`. */
19
22
  publicClient: PublicClient;
20
23
  /** A msgboard SDK client wrapping `publicClient`. */
21
24
  client: MsgBoardClient;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msgboard/relayer",
3
- "version": "0.0.1",
3
+ "version": "0.0.31",
4
4
  "description": "Controllable, safe-by-default pool-watcher relayer for the msgboard board",
5
5
  "repository": "github:valve-tech/msgboard",
6
6
  "author": "MsgBoard",
@@ -14,13 +14,18 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "exports": {
16
16
  ".": {
17
+ "types": "./dist/index.d.ts",
17
18
  "import": "./dist/index.js",
18
19
  "require": "./dist/index.js",
19
- "default": "./dist/index.js",
20
- "types": "./dist/index.d.ts"
20
+ "default": "./dist/index.js"
21
21
  }
22
22
  },
23
- "keywords": ["msgboard", "relayer", "pool-watcher", "pulsechain"],
23
+ "keywords": [
24
+ "msgboard",
25
+ "relayer",
26
+ "pool-watcher",
27
+ "pulsechain"
28
+ ],
24
29
  "scripts": {
25
30
  "prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
26
31
  "build": "tsc",
@@ -29,16 +34,21 @@
29
34
  "test:watch": "vitest",
30
35
  "lint": "prettier --check ."
31
36
  },
32
- "files": ["dist/"],
37
+ "files": [
38
+ "dist/"
39
+ ],
33
40
  "dependencies": {
34
- "@msgboard/sdk": "^0.0.28",
41
+ "@msgboard/history": "^0.0.31",
42
+ "@msgboard/sdk": "^0.0.31",
35
43
  "viem": "^2.25.0"
36
44
  },
37
45
  "peerDependencies": {
38
46
  "pg": "^8.14.1"
39
47
  },
40
48
  "peerDependenciesMeta": {
41
- "pg": { "optional": true }
49
+ "pg": {
50
+ "optional": true
51
+ }
42
52
  },
43
53
  "devDependencies": {
44
54
  "@types/pg": "^8.11.11",