@hirosystems/chainhook-client
Version:
Chainhook TypeScript client
156 lines • 7.84 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChainhookEventObserver = exports.EventObserverPredicateSchema = void 0;
const server_1 = require("./server");
const predicates_1 = require("./predicates");
const type_provider_typebox_1 = require("@fastify/type-provider-typebox");
const if_this_1 = require("./schemas/bitcoin/if_this");
const if_this_2 = require("./schemas/stacks/if_this");
const logger_1 = require("./util/logger");
const predicate_1 = require("./schemas/predicate");
const EventObserverOptionsSchema = type_provider_typebox_1.Type.Object({
/** Event observer host name (usually '0.0.0.0') */
hostname: type_provider_typebox_1.Type.String(),
/** Event observer port */
port: type_provider_typebox_1.Type.Integer(),
/** Authorization token for all Chainhook payloads */
auth_token: type_provider_typebox_1.Type.String(),
/** Base URL that will be used by Chainhook to send all payloads to this event observer */
external_base_url: type_provider_typebox_1.Type.String(),
/** Wait for the chainhook node to be available before submitting predicates */
wait_for_chainhook_node: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Boolean({ default: true })),
/** Validate the JSON schema of received chainhook payloads and report errors when invalid */
validate_chainhook_payloads: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Boolean({ default: false })),
/** Validate the authorization token sent by the server is correct. */
validate_token_authorization: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Boolean({ default: true })),
/** Size limit for received chainhook payloads (default 40MB) */
body_limit: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Number({ default: 41943040 })),
/** Node type: `chainhook` or `ordhook` */
node_type: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Union([type_provider_typebox_1.Type.Literal('chainhook'), type_provider_typebox_1.Type.Literal('ordhook')], {
default: 'chainhook',
})),
/**
* Directory where registered predicates will be persisted to disk so they can be recalled on
* restarts.
*/
predicate_disk_file_path: type_provider_typebox_1.Type.String(),
/**
* How often we should check with the Chainhook server to make sure our predicates are active and
* up to date. If they become obsolete, we will attempt to re-register them.
*/
predicate_health_check_interval_ms: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Integer({ default: 5000 })),
predicate_re_register_callback: type_provider_typebox_1.Type.Optional(type_provider_typebox_1.Type.Function([predicate_1.PredicateSchema], type_provider_typebox_1.Type.Promise(predicate_1.PredicateSchema))),
});
const ChainhookNodeOptionsSchema = type_provider_typebox_1.Type.Object({
/** Base URL where the Chainhook node is located */
base_url: type_provider_typebox_1.Type.String(),
});
const IfThisThenNothingSchema = type_provider_typebox_1.Type.Union([
type_provider_typebox_1.Type.Composite([
if_this_1.BitcoinIfThisOptionsSchema,
type_provider_typebox_1.Type.Object({
if_this: if_this_1.BitcoinIfThisSchema,
}),
]),
type_provider_typebox_1.Type.Composite([
if_this_2.StacksIfThisOptionsSchema,
type_provider_typebox_1.Type.Object({
if_this: if_this_2.StacksIfThisSchema,
}),
]),
]);
exports.EventObserverPredicateSchema = type_provider_typebox_1.Type.Composite([
type_provider_typebox_1.Type.Object({
name: type_provider_typebox_1.Type.String(),
version: type_provider_typebox_1.Type.Integer(),
chain: type_provider_typebox_1.Type.String(),
}),
type_provider_typebox_1.Type.Object({
networks: type_provider_typebox_1.Type.Object({
mainnet: type_provider_typebox_1.Type.Optional(IfThisThenNothingSchema),
testnet: type_provider_typebox_1.Type.Optional(IfThisThenNothingSchema),
}),
}),
]);
/**
* Local web server that registers predicates and receives events from a Chainhook node. It handles
* retry logic and node availability transparently and provides a callback for individual event
* processing.
*
* Predicates registered here do not accept a `then_that` entry as this will be configured
* automatically to redirect events to this server.
*
* Events relayed by this component will include the original predicate's UUID so actions can be
* taken for each relevant predicate.
*/
class ChainhookEventObserver {
constructor(observer, chainhook) {
this.observer = observer;
this.chainhook = chainhook;
}
/**
* Starts the Chainhook event observer.
* @param predicates - Predicates to register. If `predicates_disk_file_path` is enabled in the
* observer, predicates stored on disk will take precedent over those specified here.
* @param callback - Function to handle every Chainhook event payload sent by the node
*/
async start(predicates, callback) {
if (this.fastify)
return;
this.fastify = await (0, server_1.buildServer)(this.observer, this.chainhook, predicates, callback);
await this.fastify.listen({ host: this.observer.hostname, port: this.observer.port });
if (this.observer.predicate_health_check_interval_ms && this.healthCheckTimer === undefined) {
this.scheduleHealthCheck();
}
}
scheduleHealthCheck() {
this.healthCheckTimer = setTimeout(() => {
void (0, predicates_1.predicateHealthCheck)(this.observer, this.chainhook)
.catch(err => {
logger_1.logger.error(err, `ChainhookEventObserver predicate health check error`);
})
.finally(() => {
if (this.healthCheckTimer) {
this.scheduleHealthCheck();
}
});
}, this.observer.predicate_health_check_interval_ms);
}
/**
* Stop the Chainhook event server gracefully.
*/
async close() {
if (this.healthCheckTimer)
clearInterval(this.healthCheckTimer);
this.healthCheckTimer = undefined;
await this.fastify?.close();
this.fastify = undefined;
}
}
exports.ChainhookEventObserver = ChainhookEventObserver;
__exportStar(require("./schemas/bitcoin/if_this"), exports);
__exportStar(require("./schemas/bitcoin/payload"), exports);
__exportStar(require("./schemas/common"), exports);
__exportStar(require("./schemas/payload"), exports);
__exportStar(require("./schemas/predicate"), exports);
__exportStar(require("./schemas/stacks/if_this"), exports);
__exportStar(require("./schemas/stacks/payload"), exports);
__exportStar(require("./schemas/stacks/signers"), exports);
__exportStar(require("./schemas/stacks/tx_events"), exports);
__exportStar(require("./schemas/stacks/tx_kind"), exports);
__exportStar(require("./server"), exports);
//# sourceMappingURL=index.js.map