Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update prettier, add ESLint #5

Merged
merged 9 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .eslintignore

This file was deleted.

2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
CODEOWNERS
.yarn

.changeset/**/*.md
19 changes: 0 additions & 19 deletions .prettierrc

This file was deleted.

31 changes: 31 additions & 0 deletions .prettierrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = {
arrowParens: "always",
bracketSameLine: true,
bracketSpacing: true,
embeddedLanguageFormatting: "auto",
endOfLine: "lf",
htmlWhitespaceSensitivity: "css",
jsxSingleQuote: false,
printWidth: 80,
proseWrap: "preserve",
quoteProps: "as-needed",
semi: true,
singleAttributePerLine: false,
singleQuote: false,
tabWidth: 2,
trailingComma: "all",
useTabs: false,
plugins: [
"prettier-plugin-packagejson",
"@ianvs/prettier-plugin-sort-imports",
],
importOrder: [
"<BUILTIN_MODULES>",
"<THIRD_PARTY_MODULES>",
"^@(/.*)$",
"^@test(/.*)$",
"^@bench(/.*)$",
"^[.]",
],
importOrderTypeScriptVersion: "5.6.3",
};
78 changes: 78 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import path from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
import { includeIgnoreFile } from "@eslint/compat";
import eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import globals from "globals";
import tseslint from "typescript-eslint";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const gitignorePath = path.resolve(__dirname, ".gitignore");

export default tseslint.config(
includeIgnoreFile(gitignorePath),
{
ignores: [".yarn/**/*"],
},
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: {
defaultProject: "tsconfig.json",
},
tsconfigRootDir: process.cwd(),
},
},
},
{
rules: {
"@typescript-eslint/consistent-type-exports": [
"error",
{
fixMixedExportsWithInlineTypeSpecifier: false,
},
],
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-deprecated": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
ignoreRestSiblings: true,
varsIgnorePattern: "^_",
},
],
"@typescript-eslint/restrict-template-expressions": [
"error",
{
allowNumber: true,
},
],
},
},
{
files: ["**/*.cjs", "**/*.js"],
extends: [tseslint.configs.disableTypeChecked],
languageOptions: {
globals: {
...globals.node,
},
},
rules: {
"@typescript-eslint/no-require-imports": "off",
},
},
{
files: ["**/*.test.ts"],
rules: {
"@typescript-eslint/no-non-null-assertion": "off",
},
},
eslintPluginPrettierRecommended,
);
4 changes: 2 additions & 2 deletions examples/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"dependencies": {
"@xmtp/agent-starter": "workspace:*",
"axios": "^1.7.9",
"express": "^4.21.2"
"express": "^5.0.1"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/express": "^5.0.0",
"@types/node": "^22.10.9",
"typescript": "^5.7.3"
},
Expand Down
39 changes: 20 additions & 19 deletions examples/express/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import express from "express";
import { xmtpClient, type XMTP } from "@xmtp/agent-starter";
import express, { type Request, type Response } from "express";
import fetch from "node-fetch";
import { xmtpClient, XMTP } from "@xmtp/agent-starter";

async function createServer(port: number, agent: XMTP) {
const app = express();
app.use(express.json());

// Endpoint to RECEIVE encrypted messages
app.post("/receive", async (req, res) => {
try {
const { nonce, ciphertext, fromAddress } = req.body;
const decryptedMessage = await agent.decrypt(
nonce,
ciphertext,
fromAddress,
);

console.log(`Server on port ${port} decrypted:`, decryptedMessage);
return res.json({ success: true, decryptedMessage });
} catch (error) {
console.error("Error in /receive:", error);
return res.status(500).json({ error: (error as Error).message });
}
app.post("/receive", (req: Request, res: Response) => {
const { nonce, ciphertext, fromAddress } = req.body as {
nonce: string;
ciphertext: string;
fromAddress: string;
};
agent
.decrypt(nonce, ciphertext, fromAddress)
.then((decryptedMessage) => {
console.log(`Server on port ${port} decrypted:`, decryptedMessage);
res.json({ success: true, decryptedMessage });
})
.catch((error: unknown) => {
console.error("Error in /receive:", error);
res.status(500).json({ error: (error as Error).message });
});
});

return new Promise((resolve) => {
Expand Down Expand Up @@ -66,8 +67,8 @@ async function main() {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
nonce: nonce as string,
ciphertext: ciphertext as string,
nonce: nonce,
ciphertext: ciphertext,
fromAddress: agentA.address as string, // the "sender"
}),
});
Expand Down
81 changes: 41 additions & 40 deletions examples/gated-group/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Client, Message, XMTP, xmtpClient } from "@xmtp/agent-starter";
import express from "express";
import { xmtpClient, type Client, type Message } from "@xmtp/agent-starter";
import { Alchemy, Network } from "alchemy-sdk";
import express, { type Request, type Response } from "express";

const settings = {
apiKey: process.env.ALCHEMY_API_KEY, // Replace with your Alchemy API key
Expand All @@ -13,24 +13,26 @@ async function main() {
onMessage: async (message: Message) => {
if (message.typeId !== "text") return;

if (message?.content.text === "/create") {
if (message.content.text === "/create") {
console.log("Creating group");
const group = await createGroup(
agent?.client,
message?.sender?.address as string,
agent?.address as string,
agent.client,
message.sender.address,
agent.address as string,
);
console.log("Group created", group?.id);
await agent.send({
message: `Group created!\n- ID: ${group?.id}\n- Group URL: https://converse.xyz/group/${group?.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
originalMessage: message,
metadata: {},
});
return;
} else {
await agent.send({
message:
"👋 Welcome to the Gated Bot Group!\nTo get started, type /create to set up a new group. 🚀\nThis example will check if the user has a particular nft and add them to the group if they do.\nOnce your group is created, you'll receive a unique Group ID and URL.\nShare the URL with friends to invite them to join your group!",
originalMessage: message,
metadata: {},
});
}
},
Expand All @@ -39,20 +41,23 @@ async function main() {
// Endpoint to add wallet address to a group from an external source
const app = express();
app.use(express.json());
app.post("/add-wallet", async (req, res) => {
try {
const { walletAddress, groupId } = req.body;
const verified = true; // (await checkNft(walletAddress, "XMTPeople"));
if (!verified) {
console.log("User cant be added to the group");
return;
} else {
await addToGroup(groupId, agent?.client as Client, walletAddress, true);
app.post("/add-wallet", (req: Request, res: Response) => {
const { walletAddress, groupId } = req.body as {
walletAddress: string;
groupId: string;
};
// const verified = true; // (await checkNft(walletAddress, "XMTPeople"));
// if (!verified) {
// console.log("User cant be added to the group");
// return;
// } else {
addToGroup(groupId, agent.client as Client, walletAddress, true)
.then(() => {
res.status(200).send("success");
}
} catch (error: any) {
res.status(400).send(error.message);
}
})
.catch((error: unknown) => {
res.status(400).send((error as Error).message);
});
});
// Start the servfalcheer
const PORT = process.env.PORT || 3000;
Expand All @@ -63,7 +68,7 @@ async function main() {
);
});
console.log(
`XMTP agent initialized on ${agent?.address}\nSend a message on https://xmtp.chat or https://converse.xyz/dm/${agent?.address}`,
`XMTP agent initialized on ${agent.address}\nSend a message on https://xmtp.chat or https://converse.xyz/dm/${agent.address}`,
);
}

Expand All @@ -80,15 +85,15 @@ export async function createGroup(
try {
let senderInboxId = "";
await client.conversations.sync();
const conversations = await client.conversations.list();
const conversations = client.conversations.list();
console.log("Conversations", conversations.length);
const group = await client?.conversations.newGroup([
const group = await client.conversations.newGroup([
senderAddress,
clientAddress,
]);
console.log("Group created", group?.id);
console.log("Group created", group.id);
const members = await group.members();
const senderMember = members.find((member: any) =>
const senderMember = members.find((member) =>
member.accountAddresses.includes(senderAddress.toLowerCase()),
);
if (senderMember) {
Expand All @@ -98,10 +103,7 @@ export async function createGroup(
console.log("Sender not found in members list");
}
await group.addSuperAdmin(senderInboxId);
console.log(
"Sender is superAdmin",
await group.isSuperAdmin(senderInboxId),
);
console.log("Sender is superAdmin", group.isSuperAdmin(senderInboxId));
await group.send(`Welcome to the new group!`);
await group.send(`You are now the admin of this group as well as the bot`);
return group;
Expand All @@ -117,15 +119,14 @@ export async function removeFromGroup(
senderAddress: string,
): Promise<void> {
try {
let lowerAddress = senderAddress.toLowerCase();
const lowerAddress = senderAddress.toLowerCase();
const isOnXMTP = await client.canMessage([lowerAddress]);
console.warn("Checking if on XMTP: ", isOnXMTP);
if (!isOnXMTP) {
if (!isOnXMTP.get(lowerAddress)) {
console.error("You don't seem to have a v3 identity ");
return;
}
const conversation =
await client.conversations.getConversationById(groupId);
const conversation = client.conversations.getConversationById(groupId);
console.warn("removing from group", conversation?.id);
await conversation?.sync();
await conversation?.removeMembers([lowerAddress]);
Expand All @@ -137,7 +138,7 @@ export async function removeFromGroup(
let wasRemoved = true;
if (members) {
for (const member of members) {
let lowerMemberAddress = member.accountAddresses[0].toLowerCase();
const lowerMemberAddress = member.accountAddresses[0].toLowerCase();
if (lowerMemberAddress === lowerAddress) {
wasRemoved = false;
break;
Expand All @@ -162,13 +163,13 @@ export async function addToGroup(
asAdmin: boolean = false,
): Promise<void> {
try {
let lowerAddress = address.toLowerCase();
const lowerAddress = address.toLowerCase();
const isOnXMTP = await client.canMessage([lowerAddress]);
if (!isOnXMTP) {
if (!isOnXMTP.get(lowerAddress)) {
console.error("You don't seem to have a v3 identity ");
return;
}
const group = await client.conversations.getConversationById(groupId);
const group = client.conversations.getConversationById(groupId);
console.warn("Adding to group", group?.id);
await group?.sync();
await group?.addMembers([lowerAddress]);
Expand All @@ -182,7 +183,7 @@ export async function addToGroup(

if (members) {
for (const member of members) {
let lowerMemberAddress = member.accountAddresses[0].toLowerCase();
const lowerMemberAddress = member.accountAddresses[0].toLowerCase();
if (lowerMemberAddress === lowerAddress) {
console.warn("Member exists", lowerMemberAddress);
return;
Expand All @@ -204,11 +205,11 @@ export async function checkNft(
const nfts = await alchemy.nft.getNftsForOwner(walletAddress);

const ownsNft = nfts.ownedNfts.some(
(nft: any) =>
nft.contract.name.toLowerCase() === collectionSlug.toLowerCase(),
(nft) =>
nft.contract.name?.toLowerCase() === collectionSlug.toLowerCase(),
);
console.log("is the nft owned: ", ownsNft);
return ownsNft as boolean;
return ownsNft;
} catch (error) {
console.error("Error fetching NFTs from Alchemy:", error);
}
Expand Down
Loading
Loading