@msgboard/relayer 0.0.30 → 0.0.32

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
@@ -59,7 +59,9 @@ await archive.migrate()
59
59
  const recent = await archive.query({ chainId: 943, category: 'lorem', limit: 20 })
60
60
  ```
61
61
 
62
- `query()` filters by `chainId`, `category` (hex or decoded text), `since`/`until`, `contains` (substring match on decoded content), `limit`, and `offset`.
62
+ `query()` filters by `chainId`, `category` (hex or decoded text), `since`/`until`, `contains` (substring match on the decoded data text), `limit`, and `offset`.
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.
63
65
 
64
66
  ## "Write for me" relay
65
67
 
@@ -0,0 +1,41 @@
1
+ import type { RelayerAction, RelayerContext } from '../types.js';
2
+ import type { PendingTxTracker, TxFees } from '../stores/pending-tx.js';
3
+ /** What the caller's submit fn is handed: the nonce + fees to use, the item, and the runtime ctx. */
4
+ export type SubmitRequest<T> = {
5
+ item: T;
6
+ nonce: number;
7
+ fees: TxFees;
8
+ context: RelayerContext;
9
+ /** True when this is a replace-by-fee resubmission of an already-pending nonce. */
10
+ replacement: boolean;
11
+ };
12
+ export type RepricingActionOptions<T> = {
13
+ /** Tracks in-flight txs by nonce (window + RBF state). */
14
+ tracker: PendingTxTracker;
15
+ /** Pure description for observe-mode logging. */
16
+ describe: (item: T, context: RelayerContext) => string;
17
+ /** Build + send ONE tx at the given nonce/fees. Returns the tx hash. */
18
+ submit: (req: SubmitRequest<T>) => Promise<{
19
+ hash: string;
20
+ }>;
21
+ /** Initial EIP-1559 fees for a fresh settlement (e.g. read from the chain). */
22
+ initialFees: (item: T, context: RelayerContext) => Promise<TxFees>;
23
+ /** A pending tx older than this is replaced-by-fee. */
24
+ staleMs: number;
25
+ /** Stable per-item key so a re-tick of the same settlement reuses its nonce. Defaults to JSON. */
26
+ itemKey?: (item: T) => string;
27
+ /** Injectable clock (tests). */
28
+ now?: () => number;
29
+ };
30
+ /**
31
+ * Wraps a single-tx submit fn with a nonce window (pipeline multiple settlements)
32
+ * and replace-by-fee (bump a stuck tx). Generic — the relayer spec §13 deferred
33
+ * "nonce-window / repricing Action wrapper". Knows nothing about games.
34
+ *
35
+ * Safety: `describe` is pure (observe mode never submits). A submitted nonce is
36
+ * remembered; a re-tick of the same item before it mines RBFs the SAME nonce
37
+ * (never a second tx, never a forged state — it only re-sends the same calldata
38
+ * at a higher fee). When the window is full a new item is a no-op this tick.
39
+ */
40
+ export declare const repricingAction: <T>(options: RepricingActionOptions<T>) => RelayerAction<T>;
41
+ //# sourceMappingURL=repricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repricing.d.ts","sourceRoot":"","sources":["../../src/actions/repricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEvE,qGAAqG;AACrG,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,cAAc,CAAA;IACvB,mFAAmF;IACnF,WAAW,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI;IACtC,0DAA0D;IAC1D,OAAO,EAAE,gBAAgB,CAAA;IACzB,iDAAiD;IACjD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,KAAK,MAAM,CAAA;IACtD,wEAAwE;IACxE,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5D,+EAA+E;IAC/E,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAClE,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,kGAAkG;IAClG,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;IAC7B,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,SAAS,sBAAsB,CAAC,CAAC,CAAC,KAAG,aAAa,CAAC,CAAC,CAkCtF,CAAA"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Wraps a single-tx submit fn with a nonce window (pipeline multiple settlements)
3
+ * and replace-by-fee (bump a stuck tx). Generic — the relayer spec §13 deferred
4
+ * "nonce-window / repricing Action wrapper". Knows nothing about games.
5
+ *
6
+ * Safety: `describe` is pure (observe mode never submits). A submitted nonce is
7
+ * remembered; a re-tick of the same item before it mines RBFs the SAME nonce
8
+ * (never a second tx, never a forged state — it only re-sends the same calldata
9
+ * at a higher fee). When the window is full a new item is a no-op this tick.
10
+ */
11
+ export const repricingAction = (options) => {
12
+ const key = options.itemKey ?? ((item) => JSON.stringify(item));
13
+ // item-key -> the nonce we assigned it, so a re-tick reuses it for RBF
14
+ const nonceOf = new Map();
15
+ return {
16
+ describe: (item, context) => options.describe(item, context),
17
+ execute: async (item, context) => {
18
+ const k = key(item);
19
+ const existing = nonceOf.get(k);
20
+ // Already in flight: replace-by-fee iff stale, else leave it.
21
+ if (existing !== undefined) {
22
+ if (!options.tracker.isStale(existing, options.staleMs)) {
23
+ return { ok: true, ref: `nonce:${existing}`, meta: { skipped: 'still-pending' } };
24
+ }
25
+ const fees = options.tracker.bumpFees(existing);
26
+ const { hash } = await options.submit({ item, nonce: existing, fees, context, replacement: true });
27
+ options.tracker.recordSubmission(existing, { hash, ...fees });
28
+ return { ok: true, ref: hash, meta: { replacement: true, nonce: existing } };
29
+ }
30
+ // New settlement: claim a nonce from the window.
31
+ const nonce = options.tracker.claim();
32
+ if (nonce === undefined) {
33
+ return { ok: false, meta: { deferred: 'nonce-window-full' } };
34
+ }
35
+ const fees = await options.initialFees(item, context);
36
+ const { hash } = await options.submit({ item, nonce, fees, context, replacement: false });
37
+ nonceOf.set(k, nonce);
38
+ options.tracker.recordSubmission(nonce, { hash, ...fees });
39
+ return { ok: true, ref: hash, meta: { nonce } };
40
+ },
41
+ };
42
+ };
43
+ //# sourceMappingURL=repricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repricing.js","sourceRoot":"","sources":["../../src/actions/repricing.ts"],"names":[],"mappings":"AA8BA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAI,OAAkC,EAAoB,EAAE;IACzF,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,IAAO,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAClE,uEAAuE;IACvE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEzC,OAAO;QACL,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;QAC5D,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC/B,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;YACnB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;YAE/B,8DAA8D;YAC9D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACxD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,CAAA;gBACnF,CAAC;gBACD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;gBAC/C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;gBAClG,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;gBAC7D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAA;YAC9E,CAAC;YAED,iDAAiD;YACjD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;YACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,mBAAmB,EAAE,EAAE,CAAA;YAC/D,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;YACzF,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;YACrB,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;YAC1D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAA;QACjD,CAAC;KACF,CAAA;AACH,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -18,6 +18,10 @@ export { forwardMessageAction } from './actions/forward-message.js';
18
18
  export { sendValueAction } from './actions/send-value.js';
19
19
  export { webhookAction } from './actions/webhook.js';
20
20
  export { noopAction } from './actions/noop.js';
21
+ export { repricingAction } from './actions/repricing.js';
22
+ export type { RepricingActionOptions, SubmitRequest } from './actions/repricing.js';
23
+ export { createPendingTxTracker } from './stores/pending-tx.js';
24
+ export type { PendingTxTracker, PendingTx, PendingTxTrackerOptions, TxFees } from './stores/pending-tx.js';
21
25
  export { httpQueueSource } from './sources/http-queue.js';
22
26
  export type { HttpQueueSource, HttpQueueSourceOptions } from './sources/http-queue.js';
23
27
  //# 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,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"}
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,wBAAwB,CAAA;AACxD,YAAY,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAE1G,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA"}
package/dist/index.js CHANGED
@@ -14,5 +14,7 @@ export { forwardMessageAction } from './actions/forward-message.js';
14
14
  export { sendValueAction } from './actions/send-value.js';
15
15
  export { webhookAction } from './actions/webhook.js';
16
16
  export { noopAction } from './actions/noop.js';
17
+ export { repricingAction } from './actions/repricing.js';
18
+ export { createPendingTxTracker } from './stores/pending-tx.js';
17
19
  export { httpQueueSource } from './sources/http-queue.js';
18
20
  //# 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,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"}
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,wBAAwB,CAAA;AAExD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAG/D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA"}
@@ -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":"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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,46 @@
1
+ /** Fee fields for an EIP-1559 settle tx, in wei. */
2
+ export type TxFees = {
3
+ maxFeePerGas: bigint;
4
+ maxPriorityFeePerGas: bigint;
5
+ };
6
+ /** What we retain about one in-flight tx, keyed by its nonce. */
7
+ export type PendingTx = {
8
+ nonce: number;
9
+ hash: string;
10
+ fees: TxFees;
11
+ submittedAt: number;
12
+ };
13
+ export type PendingTxTrackerOptions = {
14
+ /** Max number of nonces in flight at once (the pipeline depth). */
15
+ windowSize: number;
16
+ /** First nonce this worker owns (from `getTransactionCount(account, 'pending')`). */
17
+ baseNonce: number;
18
+ /** Injectable clock for tests. Defaults to Date.now. */
19
+ now?: () => number;
20
+ /** RBF bump numerator/denominator. Defaults to 1125/1000 (+12.5%, above geth's 10% floor). */
21
+ bumpNum?: bigint;
22
+ bumpDen?: bigint;
23
+ };
24
+ /**
25
+ * Tracks settle txs by nonce so multiple settlements pipeline (a bounded window)
26
+ * and stuck ones can be replaced-by-fee. Knows nothing about games or settlement —
27
+ * a generic engine primitive (the relayer spec §13 deferred item). Process-local.
28
+ */
29
+ export type PendingTxTracker = {
30
+ /** Reserve the next nonce, or undefined if the window is full. */
31
+ claim(): number | undefined;
32
+ /** Record the tx hash + fees we submitted for a claimed nonce. */
33
+ recordSubmission(nonce: number, tx: {
34
+ hash: string;
35
+ } & TxFees): void;
36
+ /** True if the tx for `nonce` was submitted longer than `staleMs` ago and is still pending. */
37
+ isStale(nonce: number, staleMs: number): boolean;
38
+ /** Compute strictly-higher fees for a replace-by-fee resubmission of `nonce`. */
39
+ bumpFees(nonce: number): TxFees;
40
+ /** Mark a nonce's tx mined; frees the slot and advances the window. */
41
+ markMined(nonce: number): void;
42
+ /** Current pending entries, for observability. */
43
+ pending(): readonly PendingTx[];
44
+ };
45
+ export declare const createPendingTxTracker: (opts: PendingTxTrackerOptions) => PendingTxTracker;
46
+ //# sourceMappingURL=pending-tx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-tx.d.ts","sourceRoot":"","sources":["../../src/stores/pending-tx.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,MAAM,MAAM,GAAG;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,oBAAoB,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED,iEAAiE;AACjE,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAA;IAClB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,kEAAkE;IAClE,KAAK,IAAI,MAAM,GAAG,SAAS,CAAA;IAC3B,kEAAkE;IAClE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,GAAG,IAAI,CAAA;IACpE,+FAA+F;IAC/F,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;IAChD,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC/B,uEAAuE;IACvE,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,kDAAkD;IAClD,OAAO,IAAI,SAAS,SAAS,EAAE,CAAA;CAChC,CAAA;AAID,eAAO,MAAM,sBAAsB,GAAI,MAAM,uBAAuB,KAAG,gBA2CtE,CAAA"}
@@ -0,0 +1,47 @@
1
+ const ceilMul = (v, num, den) => (v * num + den - 1n) / den;
2
+ export const createPendingTxTracker = (opts) => {
3
+ const now = opts.now ?? (() => Date.now());
4
+ const bumpNum = opts.bumpNum ?? 1125n;
5
+ const bumpDen = opts.bumpDen ?? 1000n;
6
+ const inFlight = new Map(); // null = claimed, not yet submitted
7
+ let nextNonce = opts.baseNonce;
8
+ const liveCount = () => inFlight.size;
9
+ return {
10
+ claim: () => {
11
+ if (liveCount() >= opts.windowSize)
12
+ return undefined;
13
+ const nonce = nextNonce;
14
+ nextNonce += 1;
15
+ inFlight.set(nonce, null);
16
+ return nonce;
17
+ },
18
+ recordSubmission: (nonce, tx) => {
19
+ inFlight.set(nonce, {
20
+ nonce,
21
+ hash: tx.hash,
22
+ fees: { maxFeePerGas: tx.maxFeePerGas, maxPriorityFeePerGas: tx.maxPriorityFeePerGas },
23
+ submittedAt: now(),
24
+ });
25
+ },
26
+ isStale: (nonce, staleMs) => {
27
+ const e = inFlight.get(nonce);
28
+ if (!e)
29
+ return false;
30
+ return now() - e.submittedAt > staleMs;
31
+ },
32
+ bumpFees: (nonce) => {
33
+ const e = inFlight.get(nonce);
34
+ if (!e)
35
+ throw new Error(`pending-tx: no submission recorded for nonce ${nonce}`);
36
+ return {
37
+ maxFeePerGas: ceilMul(e.fees.maxFeePerGas, bumpNum, bumpDen),
38
+ maxPriorityFeePerGas: ceilMul(e.fees.maxPriorityFeePerGas, bumpNum, bumpDen),
39
+ };
40
+ },
41
+ markMined: (nonce) => {
42
+ inFlight.delete(nonce);
43
+ },
44
+ pending: () => [...inFlight.values()].filter((e) => e !== null),
45
+ };
46
+ };
47
+ //# sourceMappingURL=pending-tx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-tx.js","sourceRoot":"","sources":["../../src/stores/pending-tx.ts"],"names":[],"mappings":"AA8CA,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW,EAAU,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,CAAA;AAE3F,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAA6B,EAAoB,EAAE;IACxF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAA;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAA;IACrC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAA,CAAC,oCAAoC;IACzF,IAAI,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;IAE9B,MAAM,SAAS,GAAG,GAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAA;IAE7C,OAAO;QACL,KAAK,EAAE,GAAG,EAAE;YACV,IAAI,SAAS,EAAE,IAAI,IAAI,CAAC,UAAU;gBAAE,OAAO,SAAS,CAAA;YACpD,MAAM,KAAK,GAAG,SAAS,CAAA;YACvB,SAAS,IAAI,CAAC,CAAA;YACd,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YACzB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC9B,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE;gBAClB,KAAK;gBACL,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,IAAI,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,YAAY,EAAE,oBAAoB,EAAE,EAAE,CAAC,oBAAoB,EAAE;gBACtF,WAAW,EAAE,GAAG,EAAE;aACnB,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAC1B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC7B,IAAI,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAA;YACpB,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC,WAAW,GAAG,OAAO,CAAA;QACxC,CAAC;QACD,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAClB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC7B,IAAI,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,KAAK,EAAE,CAAC,CAAA;YAChF,OAAO;gBACL,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC;gBAC5D,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,EAAE,OAAO,EAAE,OAAO,CAAC;aAC7E,CAAA;QACH,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;KAChF,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.32",
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,31 +14,42 @@
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",
27
32
  "watch": "tsc -w",
33
+ "typecheck": "tsc --noEmit -p tsconfig.test.json",
28
34
  "test": "vitest run",
29
35
  "test:watch": "vitest",
30
36
  "lint": "prettier --check ."
31
37
  },
32
- "files": ["dist/"],
38
+ "files": [
39
+ "dist/"
40
+ ],
33
41
  "dependencies": {
34
- "@msgboard/sdk": "^0.0.30",
42
+ "@msgboard/history": "^0.0.32",
43
+ "@msgboard/sdk": "^0.0.32",
35
44
  "viem": "^2.25.0"
36
45
  },
37
46
  "peerDependencies": {
38
47
  "pg": "^8.14.1"
39
48
  },
40
49
  "peerDependenciesMeta": {
41
- "pg": { "optional": true }
50
+ "pg": {
51
+ "optional": true
52
+ }
42
53
  },
43
54
  "devDependencies": {
44
55
  "@types/pg": "^8.11.11",