Add syncing/replication example for Postgres (#938)

Provide a working end-to-end example of syncing data from hubs to a
Postgres database.

This should work with no additional dependencies besides what you
install with `yarn install` and Docker.
This commit is contained in:
Shane da Silva
2023-05-05 09:56:48 -07:00
committed by GitHub
parent 5d1fef9db7
commit cc2f5a4fae
13 changed files with 2039 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ contained repository that includes a StackBlitz link to run it in a cloud REPL.
- [Generate a chronological feed](./chron-feed/)
- [Writing data for a user](./write-data/)
- [Building casts correctly](./make-cast/)
- [Replicating data into Postgres](./replicate-data-postgres/)
Other examples that should be added:

View File

@@ -0,0 +1,17 @@
## Replicate hub data into Postgres
This example shows you how you can quickly start ingesting data from a Farcaster hub into a traditional database like Postgres.
### Run on StackBlitz
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/farcasterxyz/hubble/tree/main/packages/hub-nodejs/examples/replicate-data-postgres)
### Run locally
1. Clone the repo locally
2. Navigate to this folder with `cd packages/hub-nodejs/examples/replicate-data-postgres`
3. Run `yarn install` to install dependencies
4. Run `docker compose up -d` to start a Postgres instance ([install Docker](https://docs.docker.com/get-docker/) if you do not yet have it)
5. Run `yarn start`
To wipe your local data, run `docker compose down -v` from this directory.

View File

@@ -0,0 +1,172 @@
import { Kysely, CamelCasePlugin, Generated, GeneratedAlways, Migrator, FileMigrationProvider } from 'kysely';
import { PostgresJSDialect } from 'kysely-postgres-js';
import postgres from 'postgres';
import { MessageType, ReactionType, UserDataType, HashScheme, SignatureScheme } from '@farcaster/hub-nodejs';
import * as path from 'path';
import { promises as fs } from 'fs';
import { fileURLToPath } from 'url';
import { Logger } from './log';
import { err, ok, Result } from 'neverthrow';
export interface Database {
hubSubscriptions: {
host: string;
lastEventId: number;
};
casts: {
id: GeneratedAlways<string>;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
deletedAt: Date | null;
timestamp: Date;
fid: number;
text: string;
hash: Uint8Array;
parentHash: Uint8Array | null;
parentFid: number | null;
parentUrl: string | null;
embeds: Generated<string[]>;
mentions: Generated<number[]>;
mentionsPositions: Generated<number[]>;
};
messages: {
id: GeneratedAlways<string>;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
deletedAt: Date | null;
revokedAt: Date | null;
prunedAt: Date | null;
fid: number;
messageType: MessageType;
timestamp: Date;
hash: Uint8Array;
hashScheme: HashScheme;
signature: Uint8Array;
signatureScheme: SignatureScheme;
signer: Uint8Array;
raw: Uint8Array;
};
reactions: {
id: GeneratedAlways<string>;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
deletedAt: Date | null;
fid: number;
reactionType: ReactionType;
timestamp: Date;
hash: Uint8Array;
targetHash: Uint8Array | null;
targetFid: number | null;
targetUrl: string | null;
};
signers: {
id: GeneratedAlways<string>;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
deletedAt: Date | null;
timestamp: Date;
fid: number;
custodyAddress: Uint8Array;
signer: Uint8Array;
name: string | null;
hash: Uint8Array;
};
verifications: {
id: GeneratedAlways<string>;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
deletedAt: Date | null;
fid: number;
timestamp: Date;
hash: Uint8Array;
claim: {
address: string;
ethSignature: string;
blockHash: string;
};
};
userData: {
id: GeneratedAlways<string>;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
deletedAt: Date | null;
timestamp: Date;
fid: number;
hash: Uint8Array;
type: UserDataType;
value: string;
};
fids: {
fid: number;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
custodyAddress: Uint8Array;
};
fnames: {
fname: string;
createdAt: Generated<Date>;
updatedAt: Generated<Date>;
custodyAddress: Uint8Array;
expiresAt: Date;
};
}
export const getDbClient = (connectionString: string) => {
return new Kysely<Database>({
dialect: new PostgresJSDialect({
connectionString,
options: {
max: 10,
types: {
// BigInts will not exceed Number.MAX_SAFE_INTEGER for our use case.
// Return as JavaScript's `number` type so it's easier to work with.
bigint: {
to: 20,
from: 20,
parse: (x: any) => Number(x),
serialize: (x: any) => x.toString(),
},
},
},
postgres,
}),
plugins: [new CamelCasePlugin()],
});
};
export const migrateToLatest = async (db: Kysely<any>, log: Logger): Promise<Result<void, unknown>> => {
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
path,
migrationFolder: path.join(path.dirname(fileURLToPath(import.meta.url)), 'migrations'),
}),
});
const { error, results } = await migrator.migrateToLatest();
results?.forEach((it) => {
if (it.status === 'Success') {
log.info(`migration "${it.migrationName}" was executed successfully`);
} else if (it.status === 'Error') {
log.error(`failed to execute migration "${it.migrationName}"`);
}
});
if (error) {
log.error('failed to migrate');
log.error(error);
return err(error);
}
return ok(undefined);
};

View File

@@ -0,0 +1,22 @@
version: '3.9'
services:
postgres:
image: postgres:15-alpine # Smaller image for demonstration purposes
restart: unless-stopped
ports:
- '6543:5432' # Use a port unlikely to be in use
environment:
- POSTGRES_DB=hub
- POSTGRES_USER=app
- POSTGRES_PASSWORD=password
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready']
interval: 10s
timeout: 10s
retries: 3
volumes:
pgdata:

View File

@@ -0,0 +1,466 @@
import {
CastAddMessage,
CastRemoveMessage,
HubRpcClient,
IdRegistryEvent,
Message,
NameRegistryEvent,
ReactionAddMessage,
ReactionRemoveMessage,
SignerAddMessage,
SignerRemoveMessage,
UserDataAddMessage,
VerificationAddEthAddressMessage,
VerificationRemoveMessage,
isCastAddMessage,
isCastRemoveMessage,
isMergeIdRegistryEventHubEvent,
isMergeMessageHubEvent,
isMergeNameRegistryEventHubEvent,
isPruneMessageHubEvent,
isReactionAddMessage,
isReactionRemoveMessage,
isRevokeMessageHubEvent,
isSignerAddMessage,
isSignerRemoveMessage,
isUserDataAddMessage,
isVerificationAddEthAddressMessage,
isVerificationRemoveMessage,
getSSLHubRpcClient,
getInsecureHubRpcClient,
} from '@farcaster/hub-nodejs';
import { HubSubscriber } from './hubSubscriber';
import { Logger } from 'pino';
import { Database } from './db';
import { Kysely, sql } from 'kysely';
import { bytesToHex, farcasterTimeToDate } from './util';
type StoreMessageOperation = 'merge' | 'delete' | 'prune' | 'revoke';
export class HubReplicator {
private client: HubRpcClient;
private subscriber: HubSubscriber;
constructor(private hubAddress: string, private ssl: boolean, private db: Kysely<Database>, private log: Logger) {
this.client = this.ssl ? getSSLHubRpcClient(hubAddress) : getInsecureHubRpcClient(hubAddress);
this.subscriber = new HubSubscriber(this.client, log);
this.subscriber.on('event', async (hubEvent) => {
if (isMergeMessageHubEvent(hubEvent)) {
await this.onMergeMessage(hubEvent.mergeMessageBody.message);
for (const deletedMessage of hubEvent.mergeMessageBody.deletedMessages) {
await this.storeMessage(deletedMessage, 'delete');
}
} else if (isPruneMessageHubEvent(hubEvent)) {
await this.onPruneMessage(hubEvent.pruneMessageBody.message);
} else if (isRevokeMessageHubEvent(hubEvent)) {
await this.onRevokeMessage(hubEvent.revokeMessageBody.message);
} else if (isMergeIdRegistryEventHubEvent(hubEvent)) {
await this.onIdRegistryEvent(hubEvent.mergeIdRegistryEventBody.idRegistryEvent);
} else if (isMergeNameRegistryEventHubEvent(hubEvent)) {
await this.onNameRegistryEvent(hubEvent.mergeNameRegistryEventBody.nameRegistryEvent);
}
// Keep track of how many events we've processed.
await this.db
.insertInto('hubSubscriptions')
.values({ host: this.hubAddress, lastEventId: hubEvent.id })
.onConflict((oc) =>
oc.columns(['host']).doUpdateSet({
lastEventId: hubEvent.id,
})
)
.execute();
});
}
public async start() {
const infoResult = await this.client.getInfo({ syncStats: true });
if (infoResult.isErr() || infoResult.value.syncStats === undefined) {
throw new Error(`Unable to get information about hub ${this.hubAddress}`);
}
const { numMessages } = infoResult.value.syncStats;
this.log.info(`Syncing ${numMessages} messages from ${this.hubAddress}`);
// Start backfilling all historical data in the background
this.backfill();
// Process live events going forward, starting from the last event we
// processed (if there was one).
const subscription = await this.db
.selectFrom('hubSubscriptions')
.where('host', '=', this.hubAddress)
.select('lastEventId')
.executeTakeFirst();
this.subscriber.start(subscription?.lastEventId);
}
public stop() {
this.subscriber.stop();
}
public destroy() {
this.subscriber.destroy();
}
private async backfill() {
const maxFidResult = await this.client.getFids({ pageSize: 1, reverse: true });
if (maxFidResult.isErr()) throw new Error('Unable to backfill', { cause: maxFidResult.error });
const maxFid = maxFidResult.value.fids[0];
for (let fid = 1; fid <= maxFid; fid++) {
this.log.info(`Starting backfill for FID ${fid}`);
await this.processAllMessagesForFid(fid);
this.log.info(`Completed backfill for FID ${fid}`);
}
}
private async processAllMessagesForFid(fid: number) {
await this.client
.getIdRegistryEvent({ fid })
.then((result) => result.map((event) => this.onIdRegistryEvent(event)));
await this.client
.getCastsByFid({ fid })
.then((result) => result.map((response) => response.messages.map((message) => this.onMergeMessage(message))));
await this.client
.getReactionsByFid({ fid })
.then((result) => result.map((response) => response.messages.map((message) => this.onMergeMessage(message))));
await this.client
.getSignersByFid({ fid })
.then((result) => result.map((response) => response.messages.map((message) => this.onMergeMessage(message))));
await this.client
.getVerificationsByFid({ fid })
.then((result) => result.map((response) => response.messages.map((message) => this.onMergeMessage(message))));
await this.client
.getUserDataByFid({ fid })
.then((result) => result.map((response) => response.messages.map((message) => this.onMergeMessage(message))));
}
// More for demonstration purposes. Can always just get the latest FID
private async *getAllFids() {
let fidsResult = await this.client.getFids({ pageSize: 1000 });
for (;;) {
if (fidsResult.isErr()) {
throw new Error('Unable to backfill', { cause: fidsResult.error });
}
const { fids, nextPageToken } = fidsResult.value;
yield fids;
if (!nextPageToken) break;
fidsResult = await this.client.getFids({ pageSize: 1000, pageToken: nextPageToken });
}
}
private async storeMessage(message: Message, operation: StoreMessageOperation) {
if (!message.data) {
throw new Error('Message data is missing');
}
const now = new Date();
const messageRow = await this.db
.insertInto('messages')
.values({
fid: message.data.fid,
messageType: message.data.type,
timestamp: farcasterTimeToDate(message.data.timestamp),
hash: message.hash,
hashScheme: message.hashScheme,
signature: message.signature,
signatureScheme: message.signatureScheme,
signer: message.signer,
raw: Message.encode(message).finish(),
deletedAt: operation === 'delete' ? now : null,
prunedAt: operation === 'prune' ? now : null,
revokedAt: operation === 'revoke' ? now : null,
})
.onConflict((oc) =>
oc
.columns(['hash'])
.doUpdateSet({
updatedAt: now,
// Only the signer or message state could have changed
signature: message.signature,
signatureScheme: message.signatureScheme,
signer: message.signer,
deletedAt: operation === 'delete' ? now : null,
prunedAt: operation === 'prune' ? now : null,
revokedAt: operation === 'revoke' ? now : null,
})
.where(({ or, cmpr, ref }) =>
// Only update if a value has actually changed
or([
cmpr('excluded.signature', '!=', ref('messages.signature')),
cmpr('excluded.signatureScheme', '!=', ref('messages.signatureScheme')),
cmpr('excluded.signer', '!=', ref('messages.signer')),
cmpr('excluded.deletedAt', 'is', sql`distinct from ${ref('messages.deletedAt')}`),
cmpr('excluded.prunedAt', 'is', sql`distinct from ${ref('messages.prunedAt')}`),
cmpr('excluded.revokedAt', 'is', sql`distinct from ${ref('messages.revokedAt')}`),
])
)
)
.returning(['updatedAt', 'createdAt'])
.executeTakeFirst();
// Return boolean indicating whether this is a new message
return !!(messageRow && messageRow.updatedAt === messageRow.createdAt);
}
private async onIdRegistryEvent(event: IdRegistryEvent) {
await this.db
.insertInto('fids')
.values({ fid: event.fid, custodyAddress: event.to })
.onConflict((oc) => oc.columns(['fid']).doUpdateSet({ custodyAddress: event.to, updatedAt: new Date() }))
.execute();
}
private async onNameRegistryEvent(event: NameRegistryEvent) {
const custodyAddress = event.to;
const expiresAt = farcasterTimeToDate(event.expiry);
await this.db
.insertInto('fnames')
.values({
fname: Buffer.from(event.fname).toString('utf8'),
custodyAddress,
expiresAt,
})
.onConflict((oc) => oc.columns(['fname']).doUpdateSet({ custodyAddress, expiresAt, updatedAt: new Date() }))
.execute();
}
private async onMergeMessage(message: Message) {
this.log.debug(`Merging message ${bytesToHex(message.hash)} (type ${message.data?.type})`);
const isInitialCreation = await this.storeMessage(message, 'merge');
if (isCastAddMessage(message)) {
await this.onCastAdd(message, isInitialCreation);
} else if (isCastRemoveMessage(message)) {
await this.onCastRemove(message);
} else if (isReactionAddMessage(message)) {
await this.onReactionAdd(message, isInitialCreation);
} else if (isReactionRemoveMessage(message)) {
await this.onReactionRemove(message);
} else if (isVerificationAddEthAddressMessage(message)) {
await this.onVerificationAddEthAddress(message, isInitialCreation);
} else if (isVerificationRemoveMessage(message)) {
await this.onVerificationRemove(message);
} else if (isSignerAddMessage(message)) {
await this.onSignerAdd(message, isInitialCreation);
} else if (isSignerRemoveMessage(message)) {
await this.onSignerRemove(message);
} else if (isUserDataAddMessage(message)) {
await this.onUserDataAdd(message, isInitialCreation);
} else {
this.log.warn(`Ignoring unknown message type ${message.data?.type}`);
}
}
private async onPruneMessage(message: Message) {
this.log.debug(`Pruning message ${bytesToHex(message.hash)} (type ${message.data?.type})`);
this.storeMessage(message, 'prune');
}
private async onRevokeMessage(message: Message) {
this.log.debug(`Revoking message ${bytesToHex(message.hash)} (type ${message.data?.type})`);
this.storeMessage(message, 'revoke');
}
private async onCastAdd(message: CastAddMessage, isInitialCreation: boolean) {
await this.db
.insertInto('casts')
.values({
timestamp: farcasterTimeToDate(message.data.timestamp),
fid: message.data.fid,
text: message.data.castAddBody.text,
hash: message.hash,
parentHash: message.data.castAddBody.parentCastId?.hash,
parentFid: message.data.castAddBody.parentCastId?.fid,
parentUrl: message.data.castAddBody.parentUrl,
embeds: message.data.castAddBody.embedsDeprecated,
mentions: message.data.castAddBody.mentions,
mentionsPositions: message.data.castAddBody.mentionsPositions,
})
// Do nothing on conflict since nothing should have changed if hash is the same.
.onConflict((oc) => oc.columns(['hash']).doNothing())
.execute();
if (isInitialCreation) {
// TODO: Execute any one-time side effects, e.g. sending push
// notifications to user whose cast was replied to, etc.
}
}
private async onCastRemove(message: CastRemoveMessage) {
await this.db
.updateTable('casts')
.where('fid', '=', message.data.fid)
.where('hash', '=', message.data.castRemoveBody.targetHash)
.set({ deletedAt: farcasterTimeToDate(message.data.timestamp) })
.execute();
// TODO: Execute any cleanup side effects to remove the cast
}
private async onReactionAdd(message: ReactionAddMessage, isInitialCreation: boolean) {
await this.db
.insertInto('reactions')
.values({
fid: message.data.fid,
timestamp: farcasterTimeToDate(message.data.timestamp),
hash: message.hash,
reactionType: message.data.reactionBody.type,
targetHash: message.data.reactionBody.targetCastId?.hash,
targetFid: message.data.reactionBody.targetCastId?.fid,
targetUrl: message.data.reactionBody.targetUrl,
})
// Do nothing on conflict since nothing should have changed if hash is the same.
.onConflict((oc) => oc.columns(['hash']).doNothing())
.execute();
if (isInitialCreation) {
// TODO: Execute any one-time side effects, e.g. sending push
// notifications to user whose cast was liked, etc.
}
}
private async onReactionRemove(message: ReactionRemoveMessage) {
await this.db
.updateTable('reactions')
.where('fid', '=', message.data.fid)
.where((eb) => {
// Search based on the type of reaction
if (message.data.reactionBody.targetUrl) {
return eb.where('targetUrl', '=', message.data.reactionBody.targetUrl);
} else if (message.data.reactionBody.targetCastId) {
return eb
.where('targetFid', '=', message.data.reactionBody.targetCastId.fid)
.where('targetHash', '=', message.data.reactionBody.targetCastId.hash);
} else {
throw new Error('Reaction had neither targetUrl nor targetCastId');
}
})
.set({ deletedAt: farcasterTimeToDate(message.data.timestamp) })
.execute();
// TODO: Execute any cleanup side effects to remove the cast
}
private async onVerificationAddEthAddress(message: VerificationAddEthAddressMessage, isInitialCreation: boolean) {
await this.db
.insertInto('verifications')
.values({
fid: message.data.fid,
timestamp: farcasterTimeToDate(message.data.timestamp),
hash: message.hash,
claim: {
address: bytesToHex(message.data.verificationAddEthAddressBody.address),
ethSignature: bytesToHex(message.data.verificationAddEthAddressBody.ethSignature),
blockHash: bytesToHex(message.data.verificationAddEthAddressBody.blockHash),
},
})
// Do nothing on conflict since nothing should have changed if hash is the same.
.onConflict((oc) => oc.columns(['hash']).doNothing())
.execute();
if (isInitialCreation) {
// TODO: Execute any one-time side effects
}
// TODO: Execute any side effects that should happen any time the user
// connects the wallet (even if they are reconnecting a previously
// disconnected wallet), e.g. fetching token balances and NFTs for their
// wallet address.
}
private async onVerificationRemove(message: VerificationRemoveMessage) {
await this.db
.updateTable('verifications')
.where('fid', '=', message.data.fid)
.where(sql`claim ->> 'address'`, '=', bytesToHex(message.data.verificationRemoveBody.address))
.set({ deletedAt: farcasterTimeToDate(message.data.timestamp) })
.execute();
// TODO: Execute any cleanup side effects, e.g. updating NFT ownership
}
private async onSignerAdd(message: SignerAddMessage, isInitialCreation: boolean) {
const signerName = message.data.signerAddBody.name;
await this.db
.insertInto('signers')
.values({
fid: message.data.fid,
timestamp: farcasterTimeToDate(message.data.timestamp),
hash: message.hash,
custodyAddress: message.signer,
signer: message.data.signerAddBody.signer,
name: signerName?.length ? signerName : null, // Treat empty string signer names as not specified
})
// Do nothing on conflict since nothing should have changed if hash is the same.
.onConflict((oc) => oc.columns(['hash']).doNothing())
.execute();
if (isInitialCreation) {
// TODO: Execute any one-time side effects
}
}
private async onSignerRemove(message: SignerRemoveMessage) {
await this.db
.updateTable('signers')
.where('fid', '=', message.data.fid)
.where('signer', '=', message.data.signerRemoveBody.signer)
.set({ deletedAt: farcasterTimeToDate(message.data.timestamp) })
.execute();
// TODO: Execute any cleanup side effects
}
private async onUserDataAdd(message: UserDataAddMessage, isInitialCreation: boolean) {
await this.db
.insertInto('userData')
.values({
timestamp: farcasterTimeToDate(message.data.timestamp),
fid: message.data.fid,
hash: message.hash,
type: message.data.userDataBody.type,
value: message.data.userDataBody.value,
})
.onConflict((oc) =>
oc
.columns(['hash'])
.doUpdateSet({
timestamp: farcasterTimeToDate(message.data.timestamp),
value: message.data.userDataBody.value,
updatedAt: new Date(),
})
.where(({ or, cmpr, ref }) =>
// Only update if a value has actually changed
or([
cmpr('excluded.timestamp', '!=', ref('userData.timestamp')),
cmpr('excluded.value', '!=', ref('userData.value')),
cmpr('excluded.updatedAt', '!=', ref('userData.updatedAt')),
])
)
)
.execute();
if (isInitialCreation) {
// TODO: Execute any one-time side effects
}
}
}

View File

@@ -0,0 +1,101 @@
import { ClientReadableStream, HubEvent, HubEventType, HubRpcClient } from '@farcaster/hub-nodejs';
import { Result, ok, err } from 'neverthrow';
import { Logger } from 'pino';
import { TypedEmitter } from 'tiny-typed-emitter';
interface HubEvents {
event: (hubEvent: HubEvent) => void;
}
export class HubSubscriber extends TypedEmitter<HubEvents> {
public hubClient: HubRpcClient;
public stopped = true;
private log: Logger;
private stream: ClientReadableStream<HubEvent> | null = null;
constructor(hubClient: HubRpcClient, log: Logger) {
super();
this.hubClient = hubClient;
this.log = log;
}
public stop() {
this.stream?.cancel();
this.stopped = true;
this.log.info(`Stopped HubSubscriber`);
}
public destroy() {
if (!this.stopped) this.stop();
this.hubClient.$.close();
}
private _waitForReadyHubClient(): Promise<Result<void, unknown>> {
return new Promise((resolve) => {
this.hubClient?.$.waitForReady(Date.now() + 500, (e) => {
return e ? resolve(err(e)) : resolve(ok(undefined));
});
});
}
public async start(fromId?: number) {
this.log.info(`Starting HubSubscriber`);
const hubClientReady = await this._waitForReadyHubClient();
if (hubClientReady.isErr()) {
this.log.error(`Failed to connect to hub: ${hubClientReady.error}`);
return err(hubClientReady.error);
}
this.log.info(`Connected to hub`);
const subscribeParams: { eventTypes: HubEventType[]; fromId?: number } = {
eventTypes: [
HubEventType.MERGE_MESSAGE,
HubEventType.REVOKE_MESSAGE,
HubEventType.PRUNE_MESSAGE,
HubEventType.MERGE_ID_REGISTRY_EVENT,
HubEventType.MERGE_NAME_REGISTRY_EVENT,
],
fromId,
};
const subscribeRequest = await this.hubClient.subscribe(subscribeParams);
return subscribeRequest
.andThen((stream) => {
this.log.info(`Subscribed to hub events`);
this.stream = stream;
this.stopped = false;
stream.on('close', async () => {
this.log.info(`HubSubscriber stream closed`);
this.stopped = true;
this.stream = null;
});
void this.processStream(stream);
return ok(stream);
})
.orElse((e) => {
this.log.error(`Error starting hub stream: ${e}`);
return err(e);
});
}
/**
* Processes the stream in paused mode so hub events are processed serially and in order.
*/
private async processStream(stream: ClientReadableStream<HubEvent>) {
this.log.debug(`Started hub event stream processing`);
try {
for await (const event of stream) {
const fnLog = this.log.child({ eventId: event.id, eventType: event.type });
fnLog.debug(`Processing event ${event.id} (${event.type})`);
this.emit('event', event);
}
} catch (e: any) {
this.log.info(`Hub event stream processing halted ${e.message}`);
}
}
}

View File

@@ -0,0 +1,57 @@
import { HubReplicator } from './hubReplicator';
import { getDbClient, migrateToLatest } from './db';
import { log } from './log';
/**
* Populate the following constants with your own values.
*
* If you're running this from the examples directory, make sure you follow the
* README.
*/
const HUB_URL = 'nemes.farcaster.xyz:2283'; // URL of the Hub
const HUB_SSL = true; // Change if your hub isn't using SSL/TLS
const POSTGRES_URL = 'postgres://app:password@localhost:6543/hub';
const db = getDbClient(POSTGRES_URL);
let replicator: HubReplicator | undefined;
const shutdown = async () => {
if (replicator) {
await replicator.stop();
await replicator.destroy();
}
if (db) {
await db.destroy();
}
};
process.on('exit', (code) => {
log.info(`Exiting process with status code ${code}`);
});
for (const signal of ['SIGTERM', 'SIGINT']) {
process.once(signal, (signalName: string) => {
log.info(`Process received ${signalName}`);
process.exitCode =
// eslint-disable-next-line security/detect-object-injection
{
SIGINT: 130,
SIGTERM: 143,
}[signalName] || 1;
shutdown();
});
}
(async () => {
// Create DB tables
const result = await migrateToLatest(db, log);
if (result.isErr()) {
process.exit(1);
}
replicator = new HubReplicator(HUB_URL, HUB_SSL, db, log);
replicator.start();
})();

View File

@@ -0,0 +1,5 @@
import { pino } from 'pino';
export const log = pino();
export type Logger = pino.Logger;

View File

@@ -0,0 +1,187 @@
import { Kysely, sql } from 'kysely';
export const up = async (db: Kysely<any>) => {
await db.schema
.createTable('hubSubscriptions')
.addColumn('host', 'text', (col) => col.notNull().primaryKey())
.addColumn('last_event_id', 'bigint')
.execute();
await db.schema
.createTable('messages')
.addColumn('id', 'bigint', (col) => col.generatedAlwaysAsIdentity().primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('deletedAt', 'timestamp')
.addColumn('prunedAt', 'timestamp')
.addColumn('revokedAt', 'timestamp')
.addColumn('timestamp', 'timestamp', (col) => col.notNull())
.addColumn('messageType', sql`smallint`, (col) => col.notNull())
.addColumn('fid', 'bigint', (col) => col.notNull())
.addColumn('hash', sql`bytea`, (col) => col.notNull())
.addColumn('hashScheme', sql`smallint`, (col) => col.notNull())
.addColumn('signature', sql`bytea`, (col) => col.notNull())
.addColumn('signatureScheme', sql`smallint`, (col) => col.notNull())
.addColumn('signer', sql`bytea`, (col) => col.notNull())
.addColumn('raw', sql`bytea`, (col) => col.notNull())
.addUniqueConstraint('messages_hash_unique', ['hash'])
.execute();
await db.schema.createIndex('messages_timestamp_index').on('messages').columns(['timestamp']).execute();
await db.schema
.createTable('casts')
.addColumn('id', 'bigint', (col) => col.generatedAlwaysAsIdentity().primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('deletedAt', 'timestamp')
.addColumn('timestamp', 'timestamp', (col) => col.notNull())
.addColumn('fid', 'bigint', (col) => col.notNull())
.addColumn('hash', sql`bytea`, (col) => col.notNull())
.addColumn('parentHash', sql`bytea`)
.addColumn('parentFid', 'bigint')
.addColumn('parentUrl', 'text')
.addColumn('text', 'text', (col) => col.notNull())
.addColumn('embeds', sql`text[]`, (col) => col.notNull().defaultTo(sql`'{}'`))
.addColumn('mentions', sql`bigint[]`, (col) => col.notNull().defaultTo(sql`'{}'`))
.addColumn('mentionsPositions', sql`smallint[]`, (col) => col.notNull().defaultTo(sql`'{}'`))
.addUniqueConstraint('casts_hash_unique', ['hash'])
.addForeignKeyConstraint('casts_hash_foreign', ['hash'], 'messages', ['hash'])
.execute();
await db.schema.createIndex('casts_fid_timestamp_index').on('casts').columns(['fid', 'timestamp']).execute();
await db.schema.createIndex('casts_timestamp_index').on('casts').columns(['timestamp']).execute();
await db.schema
.createIndex('casts_parent_hash_parent_fid_index')
.on('casts')
.columns(['parentHash', 'parentFid'])
.where('parentHash', 'is not', null)
.where('parentFid', 'is not', null)
.execute();
await db.schema
.createIndex('casts_parent_url_index')
.on('casts')
.columns(['parentUrl'])
.where('parentUrl', 'is not', null)
.execute();
await db.schema
.createTable('reactions')
.addColumn('id', 'bigint', (col) => col.generatedAlwaysAsIdentity().primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('deletedAt', 'timestamp')
.addColumn('timestamp', 'timestamp', (col) => col.notNull())
.addColumn('reactionType', sql`smallint`, (col) => col.notNull())
.addColumn('fid', 'bigint', (col) => col.notNull())
.addColumn('hash', sql`bytea`, (col) => col.notNull())
.addColumn('targetHash', sql`bytea`)
.addColumn('targetFid', 'bigint')
.addColumn('targetUrl', 'text')
.addUniqueConstraint('reactions_hash_unique', ['hash'])
.addForeignKeyConstraint('reactions_hash_foreign', ['hash'], 'messages', ['hash'])
.execute();
await db.schema.createIndex('reactions_fid_timestamp_index').on('reactions').columns(['fid', 'timestamp']).execute();
await db.schema
.createIndex('reactions_target_hash_target_fid_index')
.on('reactions')
.columns(['targetHash', 'targetFid'])
.where('targetHash', 'is not', null)
.where('targetFid', 'is not', null)
.execute();
await db.schema
.createIndex('reactions_target_url_index')
.on('reactions')
.columns(['targetUrl'])
.where('targetUrl', 'is not', null)
.execute();
await db.schema
.createTable('signers')
.addColumn('id', 'bigint', (col) => col.generatedAlwaysAsIdentity().primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('deletedAt', 'timestamp')
.addColumn('timestamp', 'timestamp', (col) => col.notNull())
.addColumn('fid', 'bigint', (col) => col.notNull())
.addColumn('hash', sql`bytea`, (col) => col.notNull())
.addColumn('custodyAddress', sql`bytea`, (col) => col.notNull())
.addColumn('signer', sql`bytea`, (col) => col.notNull())
.addColumn('name', 'text')
.addUniqueConstraint('signers_hash_unique', ['hash'])
.addForeignKeyConstraint('signers_hash_foreign', ['hash'], 'messages', ['hash'])
.execute();
await db.schema.createIndex('signers_fid_timestamp_index').on('signers').columns(['fid', 'timestamp']).execute();
await db.schema
.createTable('verifications')
.addColumn('id', 'bigint', (col) => col.generatedAlwaysAsIdentity().primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('deletedAt', 'timestamp')
.addColumn('timestamp', 'timestamp', (col) => col.notNull())
.addColumn('fid', 'bigint', (col) => col.notNull())
.addColumn('hash', sql`bytea`, (col) => col.notNull())
.addColumn('claim', 'jsonb', (col) => col.notNull())
.addUniqueConstraint('verifications_hash_unique', ['hash'])
.addForeignKeyConstraint('verifications_ash_foreign', ['hash'], 'messages', ['hash'])
.execute();
await db.schema
.createIndex('verifications_claim_address_index')
.on('verifications')
.expression(sql`(claim ->> 'address'::text)`)
.execute();
await db.schema
.createIndex('verifications_fid_timestamp_index')
.on('verifications')
.columns(['fid', 'timestamp'])
.execute();
await db.schema
.createTable('userData')
.addColumn('id', 'bigint', (col) => col.generatedAlwaysAsIdentity().primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('deletedAt', 'timestamp')
.addColumn('timestamp', 'timestamp', (col) => col.notNull())
.addColumn('fid', 'bigint', (col) => col.notNull())
.addColumn('hash', sql`bytea`, (col) => col.notNull())
.addColumn('type', sql`smallint`, (col) => col.notNull())
.addColumn('value', 'text', (col) => col.notNull())
.addUniqueConstraint('user_data_hash_unique', ['hash'])
.addUniqueConstraint('user_data_fid_type_unique', ['fid', 'type'])
.addForeignKeyConstraint('user_data_hash_foreign', ['hash'], 'messages', ['hash'])
.execute();
await db.schema.createIndex('user_data_fid_index').on('user_data').columns(['fid']).execute();
await db.schema
.createTable('fids')
.addColumn('fid', 'bigint', (col) => col.primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('custodyAddress', sql`bytea`, (col) => col.notNull())
.execute();
await db.schema
.createTable('fnames')
.addColumn('fname', 'text', (col) => col.primaryKey())
.addColumn('createdAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('updatedAt', 'timestamp', (col) => col.notNull().defaultTo(sql`current_timestamp`))
.addColumn('custodyAddress', sql`bytea`, (col) => col.notNull())
.addColumn('expiresAt', 'timestamp', (col) => col.notNull())
.execute();
};
export const down = async (db: Kysely<any>) => {
await db.schema.dropTable('casts').ifExists().execute();
await db.schema.dropTable('reactions').ifExists().execute();
await db.schema.dropTable('signers').ifExists().execute();
await db.schema.dropTable('verifications').ifExists().execute();
await db.schema.dropTable('userData').ifExists().execute();
await db.schema.dropTable('messages').ifExists().execute();
};

View File

@@ -0,0 +1,22 @@
{
"name": "example-replicate-data-postgres",
"private": true,
"type": "module",
"version": "0.0.0",
"main": "index.ts",
"scripts": {
"start": "tsx index.ts"
},
"dependencies": {
"@farcaster/hub-nodejs": "^0.7.1",
"kysely": "^0.24.2",
"kysely-postgres-js": "^1.1.1",
"pino": "^8.12.1",
"postgres": "^3.3.4",
"tiny-typed-emitter": "^2.1.0"
},
"devDependencies": {
"tsx": "^3.12.5",
"typescript": "^5.0.0"
}
}

View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"noImplicitReturns": true,
}
}

View File

@@ -0,0 +1,24 @@
/* eslint-disable prefer-arrow-functions/prefer-arrow-functions */
import { fromFarcasterTime } from '@farcaster/hub-nodejs';
export function farcasterTimeToDate(time: undefined): undefined;
export function farcasterTimeToDate(time: null): null;
export function farcasterTimeToDate(time: number): Date;
export function farcasterTimeToDate(time: number | null | undefined): Date | null | undefined;
export function farcasterTimeToDate(time: number | null | undefined): Date | null | undefined {
if (time === undefined) return undefined;
if (time === null) return null;
const result = fromFarcasterTime(time);
if (result.isErr()) throw result.error;
return new Date(result.value);
}
export function bytesToHex(bytes: undefined): undefined;
export function bytesToHex(bytes: null): null;
export function bytesToHex(bytes: Uint8Array): string;
export function bytesToHex(bytes: Uint8Array | null | undefined): string | null | undefined {
if (bytes === undefined) return undefined;
if (bytes === null) return null;
return '0x' + Buffer.from(bytes).toString('hex');
}

View File

@@ -0,0 +1,953 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@adraffy/ens-normalize@1.9.0":
version "1.9.0"
resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d"
integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==
"@esbuild-kit/cjs-loader@^2.4.2":
version "2.4.2"
resolved "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz#cb4dde00fbf744a68c4f20162ea15a8242d0fa54"
integrity sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==
dependencies:
"@esbuild-kit/core-utils" "^3.0.0"
get-tsconfig "^4.4.0"
"@esbuild-kit/core-utils@^3.0.0":
version "3.1.0"
resolved "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz#49945d533dbd5e1b7620aa0fc522c15e6ec089c5"
integrity sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==
dependencies:
esbuild "~0.17.6"
source-map-support "^0.5.21"
"@esbuild-kit/esm-loader@^2.5.5":
version "2.5.5"
resolved "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz#b82da14fcee3fc1d219869756c06f43f67d1ca71"
integrity sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==
dependencies:
"@esbuild-kit/core-utils" "^3.0.0"
get-tsconfig "^4.4.0"
"@esbuild/android-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz#4aa8d8afcffb4458736ca9b32baa97d7cb5861ea"
integrity sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==
"@esbuild/android-arm@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz#74a7e95af4ee212ebc9db9baa87c06a594f2a427"
integrity sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==
"@esbuild/android-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz#1dcd13f201997c9fe0b204189d3a0da4eb4eb9b6"
integrity sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==
"@esbuild/darwin-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz#444f3b961d4da7a89eb9bd35cfa4415141537c2a"
integrity sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==
"@esbuild/darwin-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz#a6da308d0ac8a498c54d62e0b2bfb7119b22d315"
integrity sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==
"@esbuild/freebsd-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz#b83122bb468889399d0d63475d5aea8d6829c2c2"
integrity sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==
"@esbuild/freebsd-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz#af59e0e03fcf7f221b34d4c5ab14094862c9c864"
integrity sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==
"@esbuild/linux-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz#8551d72ba540c5bce4bab274a81c14ed01eafdcf"
integrity sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==
"@esbuild/linux-arm@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz#e09e76e526df4f665d4d2720d28ff87d15cdf639"
integrity sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==
"@esbuild/linux-ia32@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz#47878860ce4fe73a36fd8627f5647bcbbef38ba4"
integrity sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==
"@esbuild/linux-loong64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz#3f8fbf5267556fc387d20b2e708ce115de5c967a"
integrity sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==
"@esbuild/linux-mips64el@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz#9d896d8f3c75f6c226cbeb840127462e37738226"
integrity sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==
"@esbuild/linux-ppc64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz#3d9deb60b2d32c9985bdc3e3be090d30b7472783"
integrity sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==
"@esbuild/linux-riscv64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz#8a943cf13fd24ff7ed58aefb940ef178f93386bc"
integrity sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==
"@esbuild/linux-s390x@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz#66cb01f4a06423e5496facabdce4f7cae7cb80e5"
integrity sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==
"@esbuild/linux-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz#23c26050c6c5d1359c7b774823adc32b3883b6c9"
integrity sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==
"@esbuild/netbsd-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz#789a203d3115a52633ff6504f8cbf757f15e703b"
integrity sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==
"@esbuild/openbsd-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz#d7b998a30878f8da40617a10af423f56f12a5e90"
integrity sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==
"@esbuild/sunos-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz#ecad0736aa7dae07901ba273db9ef3d3e93df31f"
integrity sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==
"@esbuild/win32-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz#58dfc177da30acf956252d7c8ae9e54e424887c4"
integrity sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==
"@esbuild/win32-ia32@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz#340f6163172b5272b5ae60ec12c312485f69232b"
integrity sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==
"@esbuild/win32-x64@0.17.18":
version "0.17.18"
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz#3a8e57153905308db357fd02f57c180ee3a0a1fa"
integrity sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==
"@ethersproject/abstract-provider@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef"
integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==
dependencies:
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/networks" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/transactions" "^5.7.0"
"@ethersproject/web" "^5.7.0"
"@ethersproject/abstract-signer@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2"
integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==
dependencies:
"@ethersproject/abstract-provider" "^5.7.0"
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/address@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37"
integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==
dependencies:
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/keccak256" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/rlp" "^5.7.0"
"@ethersproject/base64@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c"
integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==
dependencies:
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/bignumber@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2"
integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==
dependencies:
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
bn.js "^5.2.1"
"@ethersproject/bytes@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d"
integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==
dependencies:
"@ethersproject/logger" "^5.7.0"
"@ethersproject/constants@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e"
integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==
dependencies:
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/keccak256@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a"
integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==
dependencies:
"@ethersproject/bytes" "^5.7.0"
js-sha3 "0.8.0"
"@ethersproject/logger@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892"
integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==
"@ethersproject/networks@^5.7.0":
version "5.7.1"
resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6"
integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==
dependencies:
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30"
integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==
dependencies:
"@ethersproject/logger" "^5.7.0"
"@ethersproject/rlp@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304"
integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==
dependencies:
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/signing-key@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3"
integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==
dependencies:
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
bn.js "^5.2.1"
elliptic "6.5.4"
hash.js "1.1.7"
"@ethersproject/strings@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2"
integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==
dependencies:
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/transactions@^5.7.0":
version "5.7.0"
resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b"
integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==
dependencies:
"@ethersproject/address" "^5.7.0"
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/keccak256" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/rlp" "^5.7.0"
"@ethersproject/signing-key" "^5.7.0"
"@ethersproject/web@^5.7.0":
version "5.7.1"
resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae"
integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==
dependencies:
"@ethersproject/base64" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/strings" "^5.7.0"
"@faker-js/faker@^7.6.0":
version "7.6.0"
resolved "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz#9ea331766084288634a9247fcd8b84f16ff4ba07"
integrity sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==
"@farcaster/core@0.7.1":
version "0.7.1"
resolved "https://registry.npmjs.org/@farcaster/core/-/core-0.7.1.tgz#69525a1cf4485dd5e0a24395daf1ae35fd0e38cb"
integrity sha512-2hVRWSgMDnoHFsuCzKhaTmsp7XWMk1QSE0RLjHarQYbosz6fILHB8F57fEZ0unAi0vDqgoMabvNLdkqQiO6HCQ==
dependencies:
"@ethersproject/abstract-signer" "^5.7.0"
"@faker-js/faker" "^7.6.0"
"@noble/ed25519" "^1.7.3"
"@noble/hashes" "^1.3.0"
ethers "~6.2.1"
neverthrow "^6.0.0"
viem "^0.3.2"
"@farcaster/hub-nodejs@^0.7.1":
version "0.7.1"
resolved "https://registry.npmjs.org/@farcaster/hub-nodejs/-/hub-nodejs-0.7.1.tgz#5ebe822890ebc4fe48f2ba2d58d5e2a78778ac65"
integrity sha512-w9U619g041RAuNlL+QXB52fLygBVBGClhbDP+28LbosDLShCPxxdpMC3Wtr5YiwusinXtiqR46yYTFuQBsEGag==
dependencies:
"@farcaster/core" "0.7.1"
"@grpc/grpc-js" "^1.8.13"
"@noble/hashes" "^1.3.0"
ethers "~6.2.1"
neverthrow "^6.0.0"
"@grpc/grpc-js@^1.8.13":
version "1.8.14"
resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz#4fe0f9917d6f094cf59245763c275442b182e9ad"
integrity sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==
dependencies:
"@grpc/proto-loader" "^0.7.0"
"@types/node" ">=12.12.47"
"@grpc/proto-loader@^0.7.0":
version "0.7.7"
resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.7.tgz#d33677a77eea8407f7c66e2abd97589b60eb4b21"
integrity sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==
dependencies:
"@types/long" "^4.0.1"
lodash.camelcase "^4.3.0"
long "^4.0.0"
protobufjs "^7.0.0"
yargs "^17.7.2"
"@noble/curves@0.9.0":
version "0.9.0"
resolved "https://registry.npmjs.org/@noble/curves/-/curves-0.9.0.tgz#d59713ecbb6a77381de84fb8969381fa85a7380b"
integrity sha512-OAdtHMXBp7Chl2lcTn/i7vnFX/q+hhTwDnek5NfYfZsY4LyaUuHCcoq2JlLY3BTFTLT+ZhYZalhF6ejlV7KnJQ==
dependencies:
"@noble/hashes" "1.3.0"
"@noble/curves@~0.8.3":
version "0.8.3"
resolved "https://registry.npmjs.org/@noble/curves/-/curves-0.8.3.tgz#ad6d48baf2599cf1d58dcb734c14d5225c8996e0"
integrity sha512-OqaOf4RWDaCRuBKJLDURrgVxjLmneGsiCXGuzYB5y95YithZMA6w4uk34DHSm0rKMrrYiaeZj48/81EvaAScLQ==
dependencies:
"@noble/hashes" "1.3.0"
"@noble/ed25519@^1.7.3":
version "1.7.3"
resolved "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123"
integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==
"@noble/hashes@1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183"
integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==
"@noble/hashes@1.3.0", "@noble/hashes@^1.3.0", "@noble/hashes@~1.3.0":
version "1.3.0"
resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1"
integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==
"@noble/secp256k1@1.7.1":
version "1.7.1"
resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
"@protobufjs/base64@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
dependencies:
"@protobufjs/aspromise" "^1.1.1"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/float@^1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
"@protobufjs/path@^1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
"@protobufjs/pool@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
"@scure/base@~1.1.0":
version "1.1.1"
resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
"@scure/bip32@1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.2.0.tgz#35692d8f8cc3207200239fc119f9e038e5f465df"
integrity sha512-O+vT/hBVk+ag2i6j2CDemwd1E1MtGt+7O1KzrPNsaNvSsiEK55MyPIxJIMI2PS8Ijj464B2VbQlpRoQXxw1uHg==
dependencies:
"@noble/curves" "~0.8.3"
"@noble/hashes" "~1.3.0"
"@scure/base" "~1.1.0"
"@scure/bip39@1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b"
integrity sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==
dependencies:
"@noble/hashes" "~1.3.0"
"@scure/base" "~1.1.0"
"@types/long@^4.0.1":
version "4.0.2"
resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
"@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "18.16.3"
resolved "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz#6bda7819aae6ea0b386ebc5b24bdf602f1b42b01"
integrity sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==
"@wagmi/chains@0.2.16":
version "0.2.16"
resolved "https://registry.npmjs.org/@wagmi/chains/-/chains-0.2.16.tgz#a726716e4619ec1c192b312e23f9c38407617aa0"
integrity sha512-rkWaI2PxCnbD8G07ZZff5QXftnSkYL0h5f4DkHCG3fGYYr/ZDvmCL4bMae7j7A9sAif1csPPBmbCzHp3R5ogCQ==
abitype@0.7.1:
version "0.7.1"
resolved "https://registry.npmjs.org/abitype/-/abitype-0.7.1.tgz#16db20abe67de80f6183cf75f3de1ff86453b745"
integrity sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ==
abort-controller@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
dependencies:
event-target-shim "^5.0.0"
aes-js@4.0.0-beta.3:
version "4.0.0-beta.3"
resolved "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.3.tgz#da2253f0ff03a0b3a9e445c8cbdf78e7fda7d48c"
integrity sha512-/xJX0/VTPcbc5xQE2VUP91y1xN8q/rDfhEzLm+vLc3hYvb5+qHCnpJRuFcrKn63zumK/sCwYYzhG8HP78JYSTA==
ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^4.0.0:
version "4.3.0"
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
atomic-sleep@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bn.js@^4.11.9:
version "4.12.0"
resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
bn.js@^5.2.1:
version "5.2.1"
resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
brorand@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^6.0.3:
version "6.0.3"
resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.2.1"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
elliptic@6.5.4:
version "6.5.4"
resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
hash.js "^1.0.0"
hmac-drbg "^1.0.1"
inherits "^2.0.4"
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
esbuild@~0.17.6:
version "0.17.18"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz#f4f8eb6d77384d68cd71c53eb6601c7efe05e746"
integrity sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==
optionalDependencies:
"@esbuild/android-arm" "0.17.18"
"@esbuild/android-arm64" "0.17.18"
"@esbuild/android-x64" "0.17.18"
"@esbuild/darwin-arm64" "0.17.18"
"@esbuild/darwin-x64" "0.17.18"
"@esbuild/freebsd-arm64" "0.17.18"
"@esbuild/freebsd-x64" "0.17.18"
"@esbuild/linux-arm" "0.17.18"
"@esbuild/linux-arm64" "0.17.18"
"@esbuild/linux-ia32" "0.17.18"
"@esbuild/linux-loong64" "0.17.18"
"@esbuild/linux-mips64el" "0.17.18"
"@esbuild/linux-ppc64" "0.17.18"
"@esbuild/linux-riscv64" "0.17.18"
"@esbuild/linux-s390x" "0.17.18"
"@esbuild/linux-x64" "0.17.18"
"@esbuild/netbsd-x64" "0.17.18"
"@esbuild/openbsd-x64" "0.17.18"
"@esbuild/sunos-x64" "0.17.18"
"@esbuild/win32-arm64" "0.17.18"
"@esbuild/win32-ia32" "0.17.18"
"@esbuild/win32-x64" "0.17.18"
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
ethers@~6.2.1:
version "6.2.3"
resolved "https://registry.npmjs.org/ethers/-/ethers-6.2.3.tgz#9ddee438b5949e9724ba4c5d2c3b8deb5202ce96"
integrity sha512-l1Z/Yr+HrOk+7LTeYRHGMvYwVLGpTuVrT/kJ7Kagi3nekGISYILIby0f1ipV9BGzgERyy+w4emH+d3PhhcxIfA==
dependencies:
"@adraffy/ens-normalize" "1.9.0"
"@noble/hashes" "1.1.2"
"@noble/secp256k1" "1.7.1"
aes-js "4.0.0-beta.3"
tslib "2.4.0"
ws "8.5.0"
event-target-shim@^5.0.0:
version "5.0.1"
resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
events@^3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
fast-redact@^3.1.1:
version "3.1.2"
resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz#d58e69e9084ce9fa4c1a6fa98a3e1ecf5d7839aa"
integrity sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-tsconfig@^4.4.0:
version "4.5.0"
resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.5.0.tgz#6d52d1c7b299bd3ee9cd7638561653399ac77b0f"
integrity sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==
hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3:
version "1.1.7"
resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
dependencies:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hmac-drbg@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==
dependencies:
hash.js "^1.0.3"
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
inherits@^2.0.3, inherits@^2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
isomorphic-ws@5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf"
integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==
js-sha3@0.8.0:
version "0.8.0"
resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
kysely-postgres-js@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/kysely-postgres-js/-/kysely-postgres-js-1.1.1.tgz#d53a738403632f03d3a00c115af01b62a5f8c9c1"
integrity sha512-4liHLEA1TfdGVixiW2wM4UFqv0r+F06pxpFng7xSdyl4p6lUp0099W+jotq4inovneTbVDBaFKwn+uOiORXKGQ==
kysely@^0.24.2:
version "0.24.2"
resolved "https://registry.npmjs.org/kysely/-/kysely-0.24.2.tgz#caf3be037939bd20449c0b7840e932f074b4d12c"
integrity sha512-+7eaTJNUYm2yRq1x+lEOZc+78TO35dTZ9b0dh49+Z9CTt2byMSbMiOKpwPlOyCAaHD4kILkAYWYZNywFlmBwRA==
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
long@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
long@^5.0.0:
version "5.2.3"
resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
neverthrow@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/neverthrow/-/neverthrow-6.0.0.tgz#bacd7661cade296ccc5c35760bb3b679214155b6"
integrity sha512-kPZKRs4VkdloCGQXPoP84q4sT/1Z+lYM61AXyV8wWa2hnuo5KpPBF2S3crSFnMrOgUISmEBP8Vo/ngGZX60NhA==
on-exit-leak-free@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4"
integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==
pino-abstract-transport@v1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz#cc0d6955fffcadb91b7b49ef220a6cc111d48bb3"
integrity sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==
dependencies:
readable-stream "^4.0.0"
split2 "^4.0.0"
pino-std-serializers@^6.0.0:
version "6.2.1"
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.1.tgz#369f4ae2a19eb6d769ddf2c88a2164b76879a284"
integrity sha512-wHuWB+CvSVb2XqXM0W/WOYUkVSPbiJb9S5fNB7TBhd8s892Xq910bRxwHtC4l71hgztObTjXL6ZheZXFjhDrDQ==
pino@^8.12.1:
version "8.12.1"
resolved "https://registry.npmjs.org/pino/-/pino-8.12.1.tgz#9aca3c733b221a5894ee58b2e070c66dd3e89fcf"
integrity sha512-n4F7nrEUDH0u5pjlUPkrvsN6oZOhScZWwpWPniwVkMnO6a2DhpnMNWDUlW0SawVICgrNhOf0yTNgw2lYQBsPYA==
dependencies:
atomic-sleep "^1.0.0"
fast-redact "^3.1.1"
on-exit-leak-free "^2.1.0"
pino-abstract-transport v1.0.0
pino-std-serializers "^6.0.0"
process-warning "^2.0.0"
quick-format-unescaped "^4.0.3"
real-require "^0.2.0"
safe-stable-stringify "^2.3.1"
sonic-boom "^3.1.0"
thread-stream "^2.0.0"
postgres@^3.3.4:
version "3.3.4"
resolved "https://registry.npmjs.org/postgres/-/postgres-3.3.4.tgz#09635eb9fae26dd449db9b1bd3956ef56c5b78fa"
integrity sha512-XVu0+d/Y56pl2lSaf0c7V19AhAEfpVrhID1IENWN8nf0xch6hFq6dAov5dtUX6ZD46wfr1TxvLhxLtV8WnNsOg==
process-warning@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz#008ec76b579820a8e5c35d81960525ca64feb626"
integrity sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==
process@^0.11.10:
version "0.11.10"
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
protobufjs@^7.0.0:
version "7.2.3"
resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2"
integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
"@protobufjs/codegen" "^2.0.4"
"@protobufjs/eventemitter" "^1.1.0"
"@protobufjs/fetch" "^1.1.0"
"@protobufjs/float" "^1.0.2"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/path" "^1.1.2"
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/node" ">=13.7.0"
long "^5.0.0"
quick-format-unescaped@^4.0.3:
version "4.0.4"
resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7"
integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
readable-stream@^4.0.0:
version "4.3.0"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz#0914d0c72db03b316c9733bb3461d64a3cc50cba"
integrity sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==
dependencies:
abort-controller "^3.0.0"
buffer "^6.0.3"
events "^3.3.0"
process "^0.11.10"
real-require@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78"
integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
safe-stable-stringify@^2.3.1:
version "2.4.3"
resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
sonic-boom@^3.1.0:
version "3.3.0"
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.3.0.tgz#cffab6dafee3b2bcb88d08d589394198bee1838c"
integrity sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==
dependencies:
atomic-sleep "^1.0.0"
source-map-support@^0.5.21:
version "0.5.21"
resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
split2@^4.0.0:
version "4.2.0"
resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
thread-stream@^2.0.0:
version "2.3.0"
resolved "https://registry.npmjs.org/thread-stream/-/thread-stream-2.3.0.tgz#4fc07fb39eff32ae7bad803cb7dd9598349fed33"
integrity sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==
dependencies:
real-require "^0.2.0"
tiny-typed-emitter@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5"
integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==
tslib@2.4.0:
version "2.4.0"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
tsx@^3.12.5:
version "3.12.7"
resolved "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz#b3b8b0fc79afc8260d1e14f9e995616c859a91e9"
integrity sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==
dependencies:
"@esbuild-kit/cjs-loader" "^2.4.2"
"@esbuild-kit/core-utils" "^3.0.0"
"@esbuild-kit/esm-loader" "^2.5.5"
optionalDependencies:
fsevents "~2.3.2"
typescript@^5.0.0:
version "5.0.4"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
viem@^0.3.2:
version "0.3.17"
resolved "https://registry.npmjs.org/viem/-/viem-0.3.17.tgz#2f4d01c5988f2a90ef52acb84a0dc9f7c2822538"
integrity sha512-WGJQ3rV2gMiHgwxLqeAZQ3HetSfsrkF//WezdJPnwUNXuic/c2jjB3MBk4XfYvuRUMccPfc37ORi03AmQxjscg==
dependencies:
"@adraffy/ens-normalize" "1.9.0"
"@noble/curves" "0.9.0"
"@noble/hashes" "1.3.0"
"@scure/bip32" "1.2.0"
"@scure/bip39" "1.2.0"
"@wagmi/chains" "0.2.16"
abitype "0.7.1"
isomorphic-ws "5.0.0"
ws "8.12.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
ws@8.12.0:
version "8.12.0"
resolved "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8"
integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==
ws@8.5.0:
version "8.5.0"
resolved "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yargs-parser@^21.1.1:
version "21.1.1"
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@^17.7.2:
version "17.7.2"
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"