@standard-crypto/farcaster-js-neynar
Version:
A tool for interacting with Farcaster via Neynar APIs.
296 lines • 11.4 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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NeynarV2APIClient = void 0;
const index_js_1 = require("./openapi/index.js");
const axios_1 = __importStar(require("axios"));
const logger_js_1 = require("../logger.js");
const utils_js_1 = require("../utils.js");
const BASE_PATH = 'https://api.neynar.com/v2';
class NeynarV2APIClient {
logger;
apis;
/**
* Instantiates a NeynarV1APIClient
*
* Note: A Wallet must be provided if the API client is to mint new AuthTokens
*/
constructor(apiKey, { logger = logger_js_1.silentLogger, axiosInstance, } = {}) {
this.logger = logger;
if (apiKey === '') {
throw new Error('Attempt to use an authenticated API method without first providing an api key');
}
if (axiosInstance === undefined) {
axiosInstance = axios_1.default.create();
}
axiosInstance.defaults.decompress = true;
axiosInstance.interceptors.response.use((response) => response, (error) => {
if (NeynarV2APIClient.isApiErrorResponse(error)) {
const apiErrors = error.response.data;
this.logger.warn(`API errors: ${JSON.stringify(apiErrors)}`);
}
throw error;
});
const config = new index_js_1.Configuration({
basePath: BASE_PATH,
apiKey: apiKey,
});
this.apis = {
signer: new index_js_1.SignerApi(config, undefined, axiosInstance),
feed: new index_js_1.FeedApi(config, undefined, axiosInstance),
cast: new index_js_1.CastApi(config, undefined, axiosInstance),
user: new index_js_1.UserApi(config, undefined, axiosInstance),
reaction: new index_js_1.ReactionApi(config, undefined, axiosInstance),
follow: new index_js_1.FollowsApi(config, undefined, axiosInstance),
};
}
/**
* Utility for parsing errors returned by the Neynar API servers. Returns true
* if the given error is caused by an error response from the server, and
* narrows the type of `error` accordingly.
*/
static isApiErrorResponse(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error) {
if (!(error instanceof axios_1.AxiosError))
return false;
return (error.response?.data !== undefined && 'message' in error.response.data);
}
/**
* Fetches an existing Signer. See [Neynar documentation](https://docs.neynar.com/reference/get-signer)
* for more details.
*
*/
async fetchSigner(signerUuid) {
try {
const response = await this.apis.signer.signer({ signerUuid });
return response.data;
}
catch (error) {
if (NeynarV2APIClient.isApiErrorResponse(error)) {
const status = error.response.status;
if (status === 404) {
return null;
}
}
throw error;
}
}
/**
* Creates and registers a Signer for an fid. See Neynar documentation[1](https://docs.neynar.com/reference/create-signer),[2](https://docs.neynar.com/reference/register-app-fid)
* for more details.
*/
async createSigner(developerMnemonic, deadline) {
const custodyAddress = (0, utils_js_1.mnemonicToAddress)(developerMnemonic);
const userResponse = await this.apis.user.lookupUserByCustodyAddress({ custodyAddress });
const developerFid = userResponse.data.user.fid;
const createSignerResponse = await this.apis.signer.createSigner();
const signer = createSignerResponse.data;
// default deadline is 24 hours
const defaultDeadline = Math.floor(Date.now() / 1000) + 86400;
// create signature
const signature = await (0, utils_js_1.generateSignature)(signer.public_key, developerFid, developerMnemonic, deadline ?? defaultDeadline);
const request = {
registerSignerKeyReqBody: {
signer_uuid: signer.signer_uuid,
app_fid: developerFid,
deadline: deadline ?? defaultDeadline,
signature: signature,
},
};
const response = await this.apis.signer.registerSignedKey(request);
return response.data;
}
/**
* Get reverse chronological feed for a user based on their follow graph. See [Neynar documentation](https://docs.neynar.com/reference/get-feed)
*/
async *fetchFeed(fid, options) {
let cursor;
while (true) {
const response = await this.apis.feed.feed({
feedType: options?.feedType ?? 'following',
filterType: options?.filterType,
fid: fid,
fids: options?.fids,
parentUrl: options?.parentUrl,
cursor: cursor,
limit: options?.pageSize,
});
// yield current page of casts
yield* response.data.casts;
// prep for next page
if (response.data.next.cursor === null) {
break;
}
cursor = response.data.next.cursor;
}
}
/**
* Gets information about an individual cast. See [Neynar documentation](https://docs.neynar.com/reference/get-cast)
*/
async fetchCast(castHash) {
try {
const response = await this.apis.cast.cast({
type: index_js_1.CastParamType.Hash,
identifier: castHash,
});
return response.data.cast;
}
catch (error) {
if (NeynarV2APIClient.isApiErrorResponse(error)) {
const status = error.response.status;
if (status === 404) {
return null;
}
}
throw error;
}
}
/**
* Gets information about an array of casts. See [Neynar documentation](https://docs.neynar.com/reference/get-array-of-casts)
*/
async fetchCasts(castHashes) {
try {
const response = await this.apis.cast.casts({
casts: castHashes.join(','),
});
return response.data.result.casts;
}
catch (error) {
if (NeynarV2APIClient.isApiErrorResponse(error)) {
const status = error.response.status;
if (status === 404) {
return null;
}
}
throw error;
}
}
/**
* Publishes a cast for the currently authenticated user. See [Neynar documentation](https://docs.neynar.com/reference/post-a-cast)
*/
async publishCast(signerUuid, text, options) {
const request = {
postCastReqBody: {
signer_uuid: signerUuid,
text: text,
embeds: options?.embeds,
parent: options?.replyTo,
},
};
const response = await this.apis.cast.postCast(request);
return response.data.cast;
}
/**
* Delete a cast. See [Neynar documentation](https://docs.neynar.com/reference/delete-a-cast)
*/
async deleteCast(signerUuid, castHash) {
const body = {
signer_uuid: signerUuid,
target_hash: castHash,
};
await this.apis.cast.deleteCast({ deleteCastReqBody: body });
}
/**
* Search for Usernames. See [Neynar documentation](https://docs.neynar.com/reference/search-usernames)
*/
async searchUsernames(query, viewerFid) {
const response = await this.apis.user.userSearch({
q: query,
viewerFid: viewerFid,
});
return response.data.result.users;
}
/**
* Update User Profile. See [Neynar documentation](https://docs.neynar.com/reference/update-user-profile)
*/
async updateUserProfile(signerUuid, updates) {
const response = await this.apis.user.updateUser({
updateUserReqBody: {
signer_uuid: signerUuid,
bio: updates.bio,
pfp_url: updates.pfp_url,
url: updates.url,
username: updates.username,
display_name: updates.display_name,
},
});
return response.data;
}
/**
* React to a cast. See [Neynar documentation](https://docs.neynar.com/reference/post-a-reaction)
*/
async reactToCast(signerUuid, reaction, castHash) {
const body = {
signer_uuid: signerUuid,
reaction_type: reaction === 'like' ? index_js_1.ReactionType.Like : index_js_1.ReactionType.Recast,
target: castHash,
};
const response = await this.apis.reaction.postReaction({
reactionReqBody: body,
});
return response.data;
}
/**
* Remove a reaction to a cast. See [Neynar documentation](https://docs.neynar.com/reference/delete-a-reaction)
*/
async removeReactionToCast(signerUuid, reaction, castHash) {
const body = {
signer_uuid: signerUuid,
reaction_type: reaction === 'like' ? index_js_1.ReactionType.Like : index_js_1.ReactionType.Recast,
target: castHash,
};
const response = await this.apis.reaction.deleteReaction({
reactionReqBody: body,
});
return response.data;
}
/**
* Follow users. See [Neynar documentation](https://docs.neynar.com/reference/follow-a-user)
*/
async followUsers(signerUuid, fids) {
const body = {
signer_uuid: signerUuid,
target_fids: fids,
};
const response = await this.apis.user.followUser({ followReqBody: body });
return response.data;
}
/**
* Unfollow users. See [Neynar documentation](https://docs.neynar.com/reference/unfollow-a-user)
*/
async unfollowUsers(signerUuid, fids) {
const body = {
signer_uuid: signerUuid,
target_fids: fids,
};
const response = await this.apis.user.unfollowUser({
followReqBody: body,
});
return response.data;
}
}
exports.NeynarV2APIClient = NeynarV2APIClient;
//# sourceMappingURL=NeynarV2APIClient.js.map