Skip to content

Commit

Permalink
wip: airstack
Browse files Browse the repository at this point in the history
  • Loading branch information
Complexlity committed Aug 9, 2024
1 parent 4b6ac9f commit f873cb4
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
testPlayground.ts
34 changes: 34 additions & 0 deletions data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"Socials": {
"Social": [
{
"userId": "11244",
"userAddressDetails": {
"addresses": [
"0x92622c2d23fdf169f312c61aa47eba16b4c12e0b"
],
"blockchain": "ethereum"
},
"profileDisplayName": "BFG 🎩↑🌱",
"profileName": "bfg",
"userAddress": "0x92622c2d23fdf169f312c61aa47eba16b4c12e0b",
"connectedAddresses": [
{
"address": "0xa2746b2a56f9886925c03af1d1e10b8b3dfbbe29",
"blockchain": "ethereum"
}
],
"followerCount": 9084,
"followingCount": 930,
"profileImage": "https://res.cloudinary.com/merkle-manufactory/image/fetch/c_fill,f_gif,w_112,h_112/https://imagedelivery.net/BXluQx4ige9GuW0Ia56BHw/9834b977-ec60-45b4-16ba-533ad68b8200/original",
"isFarcasterPowerUser": true
}
]
},
"Following": {
"Following": null
},
"Followedby": {
"Following": null
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"vitest": "^2.0.5"
},
"dependencies": {
"@airstack/node": "^0.0.7",
"axios": "^1.7.3",
"ky": "^1.5.0"
}
Expand Down
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { User, Cast } from "./playground";
import { services, TService, Service } from "./services";
import { neynarService } from "./services/neynar";
type Config = {
hubUrl?: string;
neynarApiKey?: string;
Expand All @@ -24,9 +23,9 @@ class uniFarcasterSdk {
//TODO: Make more composable
private createService(service?: TService): Service {
if (service === "neynar" && this.neynarApiKey) {
return new neynarService(this.neynarApiKey);
return new services.neynar(this.neynarApiKey);
} else if (service === "airstack" && this.airstackApiKey) {
return services.airstack.init(this.airstackApiKey);
return new services.airstack(this.airstackApiKey);
} else {
return services.hub;
}
Expand Down
40 changes: 18 additions & 22 deletions src/playground.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
// const uniFarcasterSdk: any = {};
const uniFarcasterSdk: any = {};

import uniFarcasterSdk from ".";

const sdk = new uniFarcasterSdk({
hubUrl: "string | hasDefaultValue",
neynarApiKey: "NEYNAR_API_DOCS",
airstackApiKey: "string | undefined",
activeService: "neynar",
neynarApiKey: "NEYNAR_API_KEY",
airstackApiKey: "AIRSTACK_API_KEY",
activeService: "airstack",
});

// const user = await sdk.getUserByFid(11244, 213144);
// // console.log(user);
const cast = await sdk.getCastByUrl(
"https://warpcast.com/timdaub.eth/0x9d6f3c51",
213144
);
console.log(cast);
// console.log(user);
// const user2: User = sdk.getUserByUsername("complexlity", 213144);
// const cast: Cast = sdk.getCastByHash("0xa0bc828", 213144);
// const cast2: Cast = sdk.getCastByUrl("https://warpcast.com/0xa38dj", 213144);

const user: User = sdk.getUserByUsername("complexlity", 213144);
const user2: User = sdk.getUserByFid(11244, 213144);
const cast: Cast = sdk.getCastByHash("0xa0bc828", 213144);
const cast2: Cast = sdk.getCastByUrl("https://warpcast.com/0xa38dj", 213144);

export type User = {
fid: number;
Expand All @@ -32,7 +25,7 @@ export type User = {
followerCount: number;
followingCount: number;
powerBadge?: boolean;
viewerContext: {
viewerContext?: {
following: boolean;
followedBy: boolean;
};
Expand All @@ -48,10 +41,13 @@ export type Cast = {
liked: boolean;
recasted: boolean;
};
text: string;
embeds: any[];
channel: string | null;
};

//Optional: Expose neynar and airstack for direct query when extra infor needed
// const endpoint = "/user?limit=2";
// const query = `SOME_GRAPHQL_QUERY`;
// sdk.neynar(endpoint);
// sdk.airstack(query);
// Optional: Expose neynar and airstack for direct query when extra infor needed
const endpoint = "/user?limit=2";
const query = `SOME_GRAPHQL_QUERY`;
sdk.neynar(endpoint);
sdk.airstack(query);
83 changes: 69 additions & 14 deletions src/services/airstack/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,85 @@
import { Service } from "..";
import { User, Cast } from "../../playground";
import { init, fetchQuery } from "@airstack/node";
import {
castByHashQuery,
castByUrlQuery,
userByFidQuery,
userByUsernameQuery,
} from "./utils";
import fs from "fs";
import { AirstackUserFetchResult } from "./types";

export const airstackService: Service = {
name: "airstack",
export class airstackService {
private apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
init(this.apiKey);
}

private getUserFromAirstackSociaslResult(data: AirstackUserFetchResult["Socials"]) {
const userDetails = data.Social[0];
const userAddresses = this.getUserAddresses(userDetails.connectedAddresses);
const convertedUser: User = {
fid: Number(userDetails.userId),
username: userDetails.profileName,
displayName: userDetails.profileDisplayName,
pfpUrl: userDetails.profileImage,
followerCount: userDetails.followerCount,
followingCount: userDetails.followingCount,
powerBadge: userDetails.isFarcasterPowerUser,
bio: userDetails.profileBio,
ethAddresses: [...userAddresses.ethAddresses, userDetails.userAddress],
solAddresses: [...userAddresses.solAddresses],
};
return convertedUser;
}

private getUserAddresses(
userAddresses: { address: string; blockchain: string }[]
) {
const ethAddresses: string[] = [];
const solAddresses: string[] = [];
for (const address of userAddresses) {
if (address.blockchain === "ethereum") {
ethAddresses.push(address.address);
}
if (address.blockchain === "solana") {
solAddresses.push(address.address);
}
}
return { ethAddresses, solAddresses };
}

async getUserByFid(fid: number, viewerFid: number): Promise<User> {
return new Promise((resolve, reject) => {
reject("Not implemented");
});
},
const query = userByFidQuery(fid, viewerFid);
const { data, error } = await fetchQuery(query);
const returnedData = data as AirstackUserFetchResult;
const user = this.getUserFromAirstackSociaslResult(returnedData.Socials);
const viewerContext = {
following: !!returnedData.Following.Following,
followedBy: !!returnedData.Followedby.Following,
}
user.viewerContext = viewerContext;
return user;
}

async getUserByUsername(username: string, viewerFid: number): Promise<User> {
return new Promise((resolve, reject) => {
reject("Not implemented");
});
},
async getUserByUsername(username: string): Promise<User> {
const query = userByUsernameQuery(username);
const { data, error } = await fetchQuery(query);
const returnedData = data as Omit<AirstackUserFetchResult, "Following" | "Followedby">;
return this.getUserFromAirstackSociaslResult(returnedData.Socials);
}

async getCastByHash(hash: string, viewerFid: number): Promise<Cast> {
return new Promise((resolve, reject) => {
reject("Not implemented");
});
},
}

async getCastByUrl(url: string, viewerFid: number): Promise<Cast> {
return new Promise((resolve, reject) => {
reject("Not implemented");
});
},
};
}
}
42 changes: 42 additions & 0 deletions src/services/airstack/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// ------------------------------------

// GENERATED TYPES FOR AIRSTACK QUERIES

// ------------------------------------

export interface AirstackUserFetchResult {
Socials: Socials;
Following: Follow;
Followedby: Follow;
}

export interface Follow {
Following: any;
}

export interface Socials {
Social: Social[];
}

export interface Social {
userId: string;
userAddress: string;
profileDisplayName: string;
profileName: string;
connectedAddresses: ConnectedAddress[];
followerCount: number;
followingCount: number;
profileImage: string;
profileBio: string;
isFarcasterPowerUser: boolean;
}

export interface ConnectedAddress {
address: string;
blockchain: string;
}

export interface UserAddressDetails {
addresses: string[];
blockchain: string;
}
Loading

0 comments on commit f873cb4

Please sign in to comment.