@msgboard/relayer 0.0.30 → 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
@@ -61,6 +61,8 @@ const recent = await archive.query({ chainId: 943, category: 'lorem', limit: 20
61
61
 
62
62
  `query()` filters by `chainId`, `category` (hex or decoded text), `since`/`until`, `contains` (substring match on decoded content), `limit`, and `offset`.
63
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
+
64
66
  ## "Write for me" relay
65
67
 
66
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.
@@ -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.chain.id,
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":"AAAA,OAAO,EAAY,WAAW,EAAE,MAAM,MAAM,CAAA;AAyC5C,8FAA8F;AAC9F,MAAM,aAAa,GAAG,CAAC,GAAQ,EAAiB,EAAE;IAChD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACzD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QAClC,qDAAqD;QACrD,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QAC9C,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAA+B,EAI/B,EAAE;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IACxB,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,CAAA;IAE5C,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACxC,MAAM,IAAI,CAAC,KAAK,CACd;;;;;;;;;;;QAWE,CACH,CAAA;QACD,MAAM,IAAI,CAAC,KAAK,CACd,wFAAwF,CACzF,CAAA;QACD,MAAM,IAAI,CAAC,KAAK,CACd,oGAAoG,CACrG,CAAA;QACD,MAAM,IAAI,CAAC,KAAK,CACd,uFAAuF,CACxF,CAAA;IACH,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,KAAK,EAAE,OAAmB,EAAE,OAAuB,EAAiB,EAAE;QACnF,MAAM,IAAI,CAAC,KAAK,CACd;;;+CAGyC,EACzC;YACE,OAAO,CAAC,IAAI;YACZ,OAAO,CAAC,KAAK,CAAC,EAAE;YAChB,OAAO,CAAC,QAAQ;YAChB,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC/B,OAAO,CAAC,IAAI;YACZ,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;YACtC,OAAO,CAAC,SAAS;SAClB,CACF,CAAA;IACH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,KAAK,IAAmB,EAAE;QACtC,MAAM,IAAI,CAAC,KAAK,CACd,uEAAuE,aAAa,QAAQ,CAC7F,CAAA;IACH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,KAAK,EAAE,MAAoB,EAA8B,EAAE;QACvE,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,MAAM,MAAM,GAAc,EAAE,CAAA;QAC5B,MAAM,GAAG,GAAG,CAAC,MAAc,EAAE,KAAc,EAAQ,EAAE;YACnD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAClB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAC5D,CAAC,CAAA;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;QACtE,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;YAAE,GAAG,CAAC,uCAAuC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAChG,IAAI,MAAM,CAAC,KAAK;YAAE,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;QACxE,IAAI,MAAM,CAAC,KAAK;YAAE,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;QACxE,IAAI,MAAM,CAAC,QAAQ;YAAE,GAAG,CAAC,kBAAkB,EAAE,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACxE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QAClG,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAChF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAC/B,+HAA+H,KAAK,sCAAsC,KAAK,WAAW,MAAM,EAAE,EAClM,MAAM,CACP,CAAA;QACD,OAAO,IAAyB,CAAA;IAClC,CAAC,CAAA;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;AAC1C,CAAC,CAAA"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msgboard/relayer",
3
- "version": "0.0.30",
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.30",
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",